5

for dynamic values sometimes the value will be keep repeating, say if a variable

table = [
    {'man':'tim','age':'2','h':'5','w':'40'},
    {'man':'jim','age':'4','h':'3','w':'20'},
    {'man':'jon','age':'24','h':'5','w':'80'}, 
    {'man':'tim','age':'2','h':'5','w':'40'},
    {'man':'tto','age':'7','h':'4','w':'49'}    
]

here {'man':'tim','age':'2','h':'5','w':'40'} dictionary set repeat twice these are dynamic value.

How can I stop repeating this, so list will not contain any repeated dictionary before rendering it to templates?

edited: actual data

[{'scorecardid': 1, 'progress2': 'preview', 'series2': 'Afghanistan v Zimbabwe in UAE, 2018', 'Commentary1': '/Commentary1', 'commentaryid': 1, 'matchid2': '10', 'matchno2': '5th ODI', 'teams2': 'AFG vs ZIM', 'matchtype2': 'ODI', 'Scorecard1': '/Scorecard1', 'status2': 'Starts on Feb 19 at 10:30 GMT'}, {'six2': '0', 'scorecardid': 2, 'overs5': '4', 'fours1': '0', 'overs10': '20', 'Batting_team_img': 'images/RSA.png', 'wickets20': '5', 'wickets6': '1', 'Bowling_team_img': 'images/IND.png', 'maidens6': '0', 'Batting team': 'RSA', 'matchid2': '9', 'name6': 'Unadkat', 'teams2': 'RSA vs IND', 'wickets10': '9', 'desc10': 'Inns', 'runs5': '32', 'matchtype2': 'T20', 'Scorecard1': '/Scorecard2', 'runs1': '2', 'wickets5': '0', 'runs6': '33', 'runs2': '0', 'maidens5': '0', 'runs20': '203', 'name5': 'Bumrah*', 'progress2': 'complete', 'Commentary1': '/Commentary2', 'fours2': '0', 'series2': 'India tour of South Africa, 2017-18', 'name1': 'Junior Dala*', 'commentaryid': 2, 'matchno2': '1st T20I', 'six1': '0', 'overs6': '4', 'Bowling team': 'IND', 'balls2': '2', 'balls1': '3', 'name2': 'Shamsi', 'overs20': '20', 'runs10': '175', 'desc20': 'Inns', 'status2': 'Ind won by 28 runs'}, {'scorecardid': 3, 'overs5': '0.4', 'fours1': '0', 'overs10': '18.4', 'Batting_team_img': 'images/BAN.png', 'wickets20': '4', 'wickets6': '1', 'Bowling_team_img': 'images/SL.png', 'Batting team': 'BAN', 'matchid2': '6', 'name6': 'Shanaka', 'teams2': 'BAN vs SL', 'wickets10': '10', 'desc10': 'Inns', 'runs5': '3', 'matchtype2': 'T20', 'Scorecard1': '/Scorecard3', 'runs1': '1', 'wickets5': '2', 'runs6': '5', 'maidens5': '0', 'runs20': '210', 'progress2': 'complete', 'Commentary1': '/Commentary3', 'name5': 'Gunathilaka*', 'series2': 'Sri Lanka tour of Bangladesh, 2018', 'name1': 'Nazmul Islam', 'commentaryid': 3, 'matchno2': '2nd T20I', 'six1': '0', 'overs6': '1.5', 'Bowling team': 'SL', 'maidens6': '0', 'balls1': '1', 'overs20': '20', 'runs10': '135', 'desc20': 'Inns', 'status2': 'SL won by 75 runs'}, {'six2': '2', 'scorecardid': 4, 'overs5': '4', 'fours1': '1', 'overs10': '20', 'Batting_team_img': 'images/NZ.png', 'wickets20': '7', 'wickets6': '1', 'Bowling_team_img': 'images/ENG.png', 'maidens6': '0', 'Batting team': 'NZ', 'matchid2': '4', 'name6': 'Tom Curran', 'teams2': 'NZ vs ENG', 'wickets10': '4', 'desc10': 'Inns', 'runs5': '41', 'matchtype2': 'T20', 'Scorecard1': '/Scorecard4', 'runs1': '7', 'wickets5': '0', 'runs6': '32', 'runs2': '37', 'maidens5': '0', 'runs20': '194', 'name5': 'Chris Jordan*', 'progress2': 'complete', 'Commentary1': '/Commentary4', 'fours2': '2', 'series2': 'England, Australia, New Zealand T20I Tri-Series, 2018', 'name1': 'de Grandhomme*', 'commentaryid': 4, 'matchno2': '6th Match', 'six1': '0', 'overs6': '3', 'Bowling team': 'ENG', 'balls2': '30', 'balls1': '5', 'name2': 'Chapman', 'overs20': '20', 'runs10': '192', 'desc20': 'Inns', 'status2': 'Eng won by 2 runs'}, {'scorecardid': 5, 'overs5': '7.4', 'fours1': '3', 'runs20': '213', 'six2': '0', 'commentaryid': 5, 'Batting team': 'SAUS', 'matchid2': '18770', 'matchno2': '21st Match', 'wickets10': '3', 'overs10': '49.4', 'matchtype2': 'TEST', 'runs1': '26', 'overs6': '8', 'runs6': '39', 'runs2': '49', 'name1': 'Mennie*', 'name5': 'Daniel Fallins*', 'series2': 'Sheffield Shield, 2017-18', 'Commentary1': '/Commentary5', 'wickets6': '1', 'runs11': '281', 'six1': '0', 'runs10': '192', 'balls1': '58', 'overs11': '74.1', 'maidens5': '1', 'desc21': '1st Inns', 'status2': 'South Aus won by 7 wkts', 'runs5': '51', 'wickets11': '10', 'desc11': '1st Inns', 'desc20': '2nd Inns', 'wickets20': '10', 'wickets21': '10', 'teams2': 'NSW vs SAUS', 'balls2': '85', 'Scorecard1': '/Scorecard5', 'wickets5': '1', 'progress2': 'Result', 'runs21': '256', 'fours2': '6', 'desc10': '2nd Inns', 'name6': 'Stobo', 'maidens6': '1', 'Bowling team': 'NSW', 'name2': 'Ferguson', 'overs20': '68.4', 'overs21': '90.4'}, {'six2': '0', 'scorecardid': 6, 'overs5': '4', 'fours1': '0', 'overs10': '20', 'Batting_team_img': 'images/RSA.png', 'wickets20': '5', 'wickets6': '1', 'Bowling_team_img': 'images/IND.png', 'maidens6': '0', 'Batting team': 'RSA', 'matchid2': '19166', 'name6': 'Unadkat', 'teams2': 'RSA vs IND', 'wickets10': '9', 'desc10': 'Inns', 'runs5': '32', 'matchtype2': 'T20', 'Scorecard1': '/Scorecard6', 'runs1': '2', 'wickets5': '0', 'runs6': '33', 'runs2': '0', 'maidens5': '0', 'runs20': '203', 'name5': 'Bumrah*', 'progress2': 'Result', 'Commentary1': '/Commentary6', 'fours2': '0', 'series2': 'India tour of South Africa, 2017-18', 'name1': 'Junior Dala*', 'commentaryid': 6, 'matchno2': '1st T20I', 'six1': '0', 'overs6': '4', 'Bowling team': 'IND', 'balls2': '2', 'balls1': '3', 'name2': 'Shamsi', 'overs20': '20', 'runs10': '175', 'desc20': 'Inns', 'status2': 'Ind won by 28 runs'}]
davidism
  • 121,510
  • 29
  • 395
  • 339
steve
  • 139
  • 2
  • 13
  • 1
    Does order matter? – cs95 Feb 19 '18 at 02:11
  • yeah first priority will be recent value, recent value will be first set – steve Feb 19 '18 at 02:12
  • What have you tried? Have you seen [this thread](https://stackoverflow.com/questions/8749158/removing-duplicates-from-dictionary) or [this site](https://www.w3resource.com/python-exercises/dictionary/python-data-type-dictionary-exercise-17.php)? Just Googling around.... – BruceWayne Feb 19 '18 at 02:13
  • 1
    @damores, that is not a duplicate since it already had a unique element. – Stephen Rauch Feb 19 '18 at 02:25
  • 1
    You are correct. Although the latest edit showing the data kind of hints at the data having an id. Maybe OP @steve can confirm if each dictionary has a unique id? – damores Feb 19 '18 at 02:35
  • 2
    no they don't have any unique ID that occurs in a order @damores – steve Feb 19 '18 at 02:46

4 Answers4

4

Since your records do not appear to have a unique identifier to differentiate records, you will need to hash on all key-value pairs. This approach will work as long as you do not have nested mutable objects inside your dictionaries.

I'll use an OrderedDict here to maintain order.

from collections import OrderedDict
list(
     map(
         dict, 
         OrderedDict.fromkeys(
             map(frozenset, map(dict.items, table)), None
         )
     )
)

[{'age': '2', 'h': '5', 'man': 'tim', 'w': '40'},
 {'age': '4', 'h': '3', 'man': 'jim', 'w': '20'},
 {'age': '24', 'h': '5', 'man': 'jon', 'w': '80'},
 {'age': '7', 'h': '4', 'man': 'tto', 'w': '49'}]

Here's what's going on:

  1. Convert each dictionary to a frozenset of tuples. frozensets are hashable.
  2. Hash each frozenset as a key into an OrderedDict. Duplicates are removed automatically.
  3. Retrieve keys and convert back into a list of dictionaries.

There are many ways to reproduce the algorithm described above. I've used the functional programming tool - map - which python offers.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • It doesn't seems to work for me, I have put actual data please check the question – steve Feb 19 '18 at 02:28
  • @coldspeed I'm getting this error descriptor 'items' requires a 'dict' object but received a 'str' – steve Feb 19 '18 at 02:35
  • @steve Aha... is that JSON? You will need to do this first: `import json; tables = json.loads(tables)` – cs95 Feb 19 '18 at 02:35
  • @cᴏʟᴅsᴘᴇᴇᴅ JSON uses `"`, not `'`. – Stefan Pochmann Feb 19 '18 at 02:36
  • @coldspeed table = json.loads(table) list(map(dict, OrderedDict.fromkeys(map(frozenset, map(dict.items, table)), None).keys())) gamest.append(table) print(gamest) TypeError: the JSON object must be str, not 'dict' – steve Feb 19 '18 at 02:43
  • That `.keys()` isn't needed, is it? – Stefan Pochmann Feb 19 '18 at 02:50
  • 1
    I don't know what your problem is, one comment says something and another comment says something else :/ – cs95 Feb 19 '18 at 02:50
  • @coldspeed sorry for mis-confusion before I didn't assign the result back so I got that error, now I'm getting error TypeError: the JSON object must be str, not 'dict' – steve Feb 19 '18 at 02:59
  • @steve So is it a string or a dictionary or a list of strings or a list of dictionaries?! – cs95 Feb 19 '18 at 03:02
  • @coldspeed it contains strings too I didn't see that {'Commentary1': '/Commentary1', 'matchtype2': 'ODI', 'matchno2': '5th ODI', 'commentaryid': 1, 'status2': 'Starts on Feb 19 at 10:30 GMT', 'teams2': 'AFG vs ZIM', 'scorecardid': 1, 'series2': 'Afghanistan v Zimbabwe in UAE, 2018', 'progress2': 'preview', 'matchid2': '10', 'Scorecard1': '/Scorecard1'} – steve Feb 19 '18 at 03:12
  • 'scorecardid': 1 which is a string – steve Feb 19 '18 at 03:13
  • @steve Yes, but that looks like a key in a dictionary, so that's okay. Do your list items also have strings...? – cs95 Feb 19 '18 at 03:13
  • @coldspeed I don't see one, but all those dictionary are not unique I have one different set {'teams2': 'AFG vs ZIM', 'scorecardid': 1, 'status2': 'Starts on Feb 19 at 10:30 GMT', 'Scorecard1': '/Scorecard1', 'series2': 'Afghanistan v Zimbabwe in UAE, 2018', 'Commentary1': '/Commentary1', 'progress2': 'preview', 'matchno2': '5th ODI', 'matchtype2': 'ODI', 'matchid2': '10', 'commentaryid': 1} – steve Feb 19 '18 at 03:22
  • followed by similar set {'Batting team': 'RSA', 'scorecardid': 2, 'Commentary1': '/Commentary2', 'name1': 'Junior Dala*', 'runs10': '175', 'status2': 'Ind won by 28 runs', 'overs10': '20', 'runs20': '203', 'series2': 'India tour of South Africa, 2017-18', 'six1': '0', 'balls2': '2', 'overs6': '4', 'overs20': '20', 'Bowling team': 'IND', 'maidens6': '0', 'wickets20': '5', 'fours2': '0', 'progress2': 'complete', 'wickets6': '1', 'matchno2': '1st T20I', 'runs2': '0', 'matchid2': '9', 'runs5': '32', 'wickets5': '0', 'Batting_team_img': 'images/RSA.png', 'teams2': 'RSA vs IND', – steve Feb 19 '18 at 03:23
  • .....'Bowling_team_img': 'images/IND.png', 'runs1': '2', 'Scorecard1': '/Scorecard2', 'name6': 'Unadkat', 'overs5': '4', 'runs6': '33', 'balls1': '3', 'name2': 'Shamsi', 'desc20': 'Inns', 'six2': '0', 'desc10': 'Inns', 'maidens5': '0', 'name5': 'Bumrah*', 'fours1': '0', 'matchtype2': 'T20', 'commentaryid': 2, 'wickets10': '9'}, Does It make any changes? – steve Feb 19 '18 at 03:23
  • @steve If your input was a list of only dictionaries with the EXACT same keys, then this should work :) – cs95 Feb 19 '18 at 03:31
2

You can find and remove the dupes if you can hash them into a set. One way to do that:

Code:

def remove_dupes(a_list):
    already_have = set()
    new_table = []
    for row in a_list:
        row_hashable = tuple(sorted(row.items()))
        if row_hashable not in already_have:
            new_table.append(row)
            already_have.add(row_hashable)
    return new_table

Test Code:

table = [
    {'man': 'tim', 'age': '2', 'h': '5', 'w': '40'},
    {'man': 'jim', 'age': '4', 'h': '3', 'w': '20'},
    {'man': 'jon', 'age': '24', 'h': '5', 'w': '80'},
    {'man': 'tim', 'age': '2', 'h': '5', 'w': '40'},
    {'man': 'tto', 'age': '7', 'h': '4', 'w': '49'}
]

print(remove_dupes(table))

Results:

[    
    {'man': 'tim', 'age': '2', 'h': '5', 'w': '40'}, 
    {'man': 'jim', 'age': '4', 'h': '3', 'w': '20'}, 
    {'man': 'jon', 'age': '24', 'h': '5', 'w': '80'},
    {'man': 'tto', 'age': '7', 'h': '4', 'w': '49'}
]
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
  • thanks @stephen rauch for answering this doesn't work for my actual data, see the question, I get error saying AttributeError: 'str' object has no attribute 'items' – steve Feb 19 '18 at 03:01
  • @steve, so I answered your question. Then you changed your question? Why? Where does that sort of merry-go-round end? You may enjoy this sort of game where the target is constantly moving. But I do not. Decide on your question, then ask. Please don't waste answer's time by changing your mid. – Stephen Rauch Feb 19 '18 at 03:04
  • sorry for that , first I thought I can explain the question using simple data but it didn't seem to work so I posted actual data, I changed only a data but not the question. – steve Feb 19 '18 at 03:33
2
list(map(dict, {tuple(sorted(t.items())):1 for t in table}.keys()))

or, using sets:

list(map(dict, set(tuple(sorted(t.items())) for t in table)))

Above solutions do not maintain order in Python < 3.6 as pointed out by @cᴏʟᴅsᴘᴇᴇᴅ.

Below is a solution that will maintain order:

singlev = []
for k, v in enumerate([tuple(sorted(t.items())) for t in table]):
    if v not in singlev:
        singlev.append(table[k])
AGN Gazer
  • 8,025
  • 2
  • 27
  • 45
0

Since your values are all hashable, you can convert to a set of "tuples of tuples", remove duplicates in order, and then convert back to dictionaries.

def uniqifier(seq):
    seen = set()
    seen_add = seen.add
    return (x for x in seq if not (x in seen or seen_add(x)))

[dict(i) for i in uniqifier(tuple(i.items()) for i in table)]

The uniquifier function is courtesy of @MarkusJarderot. The only modification I made is to use it to return a generator rather than a list.

jpp
  • 159,742
  • 34
  • 281
  • 339