4

If I have a dictionary {key : [a b c c d]} and I want to print only the unique values corresponding to each key (In this case, (a,b,d)) what is the most efficient way to do this apart from just looping through each element and keeping a count of it?

2rs2ts
  • 10,662
  • 10
  • 51
  • 95
vkaul11
  • 4,098
  • 12
  • 47
  • 79
  • 1
    Don't you mean `(a,b,c,d)` in this case? – arshajii Jun 20 '13 at 16:26
  • 1
    Is this a repeat of [Print all Unique Values in a Python Dictionary](http://stackoverflow.com/q/17218139) is it? – Martijn Pieters Jun 20 '13 at 16:27
  • 1
    No I meant exactly printing only (a,b,d). I don't want to print c. – vkaul11 Jun 20 '13 at 16:31
  • I think OP's question was pretty clear and explicit. No counting, and only elements which are unique (occur only once). Not each element in the list, excluding duplicates. – 2rs2ts Jun 20 '13 at 16:36
  • Can't be done without counting, unless you have more restrictions on the list. Is it guaranteed to be sorted/partitioned? –  Jun 20 '13 at 16:39
  • @Rhymoid I beg to differ 8) – 2rs2ts Jun 20 '13 at 16:46
  • 1
    With such (strange) requirements, it's always useful to state why you have them. What's the problem with using a `Counter`? – Thijs van Dien Jun 20 '13 at 16:50
  • @2rs2ts: I think counting in the lattice of `[0, 1, many]` under `<=` is unavoidable. For instance, `a` is not unique in `[a, b, c, d, a]`, but you always need to keep track of the fact that `a` already occurs in the list (regardless of the way you combine the sub-answers). Not so with lists where equal elements are always found together, then you just have to count the length of each run, for which you only need constant space. –  Jun 20 '13 at 16:51
  • @Rhymoid I agree, but, it's not that it's not *possible*. :) – 2rs2ts Jun 20 '13 at 16:55

7 Answers7

3

If elements are sorted as in your example; you could use itertools.groupby():

from itertools import groupby

print " ".join([k for k, group in groupby(d['key']) if len(list(group)) == 1])
# -> a b d
jfs
  • 399,953
  • 195
  • 994
  • 1,670
2

One option, use collections.Counter

from collections import Counter
d = {'k': ['a', 'b', 'c', 'c', 'd']}
c = Counter(d['k'])
print [k for k in c if c[k] == 1]
['a', 'b', 'd']
iruvar
  • 22,736
  • 7
  • 53
  • 82
  • 2
    If you read the source code for `Counter`, it just does "looping through each element and keeping a count of it", which the OP didn't want. – Aya Jun 20 '13 at 16:35
  • @1_CR thanks for understanding my question at least. I got downvotes from people who did not even understand my question. – vkaul11 Jun 20 '13 at 16:35
  • 1
    @vkaul11 I upvoted to compensate. I think your question, while hard to find a use case for it, is quite legitimate and clearly worded. Python devs on SO just like to use Counter and sets. :P – 2rs2ts Jun 20 '13 at 16:38
0

You can use Counter from collections:

>>> d = {'key': ['a', 'b', 'c', 'c', 'd']}
>>> 
>>> from collections import Counter
>>> 
>>> new_dict = Counter(d['key'])
>>> new_dict
Counter({'c': 2, 'a': 1, 'b': 1, 'd': 1})
>>> [elem for elem in new_dict.keys() if new_dict[elem] == 1]
['a', 'b', 'd']
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
0

Not using a Counter:

unique = []
for i, val in enumerate(d['key']):
    if item not in d['key'][i+1:] and item not in d['key'][:i]:
        unique.append(item)

Using a generator comprehension:

unique = list((d['key'][i] for i in range(len(d['key'])) if d['key'][i] not in d['key'][i+1:] and d['key'][i] not in d['key'][:i]))
2rs2ts
  • 10,662
  • 10
  • 51
  • 95
  • Pretty innovative solution I must say. – vkaul11 Jun 20 '13 at 16:38
  • 8
    This algorithm is O(n²), which is even less efficient than than using a Counter, which is O(n). – Aya Jun 20 '13 at 16:42
  • What about sorting before so you can only check the next and previous value? – Maxime Chéramy Jun 20 '13 at 16:43
  • 1
    @Maxime Well, sorting adds an O(n log n) time complexity to whatever else you're going to do. – Aya Jun 20 '13 at 16:44
  • @Aya what makes my first part O(n^2)? Use of enumerate? – 2rs2ts Jun 20 '13 at 16:45
  • Yes, sorry, it was not an answer to your comment. You are most probably right, Counter sounds to be a better solution anyway. Just saying that complexity would be still better than O(n^2) and still no counting as asking by OP. – Maxime Chéramy Jun 20 '13 at 16:46
  • 3
    @2rs2ts `item not in d['key'][i+1:]` does an O(n) search of the list. – Aya Jun 20 '13 at 16:46
  • @Aya ah, fair enough! Quite an oversight of mine. I'd personally use counting anyway, but, it's not my place to tell OP what to do instead, but rather just tell him how to do what he's asking. – 2rs2ts Jun 20 '13 at 16:48
0

Assuming the list is sorted:

>>> L = [1, 1, 2, 3, 4, 4, 4, 5]
>>> [e for i, e in enumerate(L) if e == L[i-1] and i < len(L)-1 and not e == L[i+1]]
[1, 4]
michaelmeyer
  • 7,985
  • 7
  • 30
  • 36
-1

You could use a set() to find all the unique elements in each list.

for key in mydict:
    uniques = set(mydict[key])
FastTurtle
  • 2,301
  • 19
  • 19
  • Again, I only want to print the unique elements and not print the duplicate elements at all. Here you will print all elements though you will print the duplicates only once. – vkaul11 Jun 20 '13 at 16:30
  • What you want is to print only the elements that appear once. This is different from printing a list of the unique elements. – FastTurtle Jun 20 '13 at 16:53
-2

In Python, you can leverage a set (a set can not have repeating elements) to find the unique elements in each key and then turn the set back into a list

for key in dict:
    print list(set(dict[key]))
Suhail Patel
  • 13,644
  • 2
  • 44
  • 49
  • I want to print only the elements that are unique like I said above if there is (a,b,c,c,d) in the list I only want to print (a,b,d) and not print c. – vkaul11 Jun 20 '13 at 16:29