I've got a problem , and do not know how to code in python.
I've got a list[10, 10, 10, 20, 20, 20, 30]
I want it be in a dictionary like this
{"10": 1, "20": 3, "30" : 1}
How could I achieve this?
from collections import Counter
a = [10, 10, 10, 20, 20, 20, 30]
c = Counter(a)
# Counter({10: 3, 20: 3, 30: 1})
If you really want to convert the keys to strings, that's a separate step:
dict((str(k), v) for k, v in c.iteritems())
This class is new to Python 2.7; for earlier versions, use this implementation:
http://code.activestate.com/recipes/576611/
Edit: Dropping this here since SO won't let me paste code into comments,
from collections import defaultdict
def count(it):
d = defaultdict(int)
for j in it:
d[j] += 1
return d
Another way that does not use set or Counter:
d = {}
x = [10, 10, 10, 20, 20, 20, 30]
for j in x:
d[j] = d.get(j,0) + 1
EDIT: For a list of size 1000000 with 100 unique items, this method runs on my laptop in 0.37 sec, while the answer using set takes 2.59 sec. For only 10 unique items, the former method takes 0.36 sec, while the latter method only takes 0.25 sec.
EDIT: The method using defaultdict takes 0.18 sec on my laptop.
Like this
l = [10, 10, 10, 20, 20, 20, 30]
uniqes = set(l)
answer = {}
for i in uniques:
answer[i] = l.count(i)
answer is now the dictionary that you want
Hope this helps
in Python >= 2.7 you can use dict comprehensions, like:
>>> l = [10, 10, 10, 20, 20, 20, 30]
>>> {x: l.count(x) for x in l}
{10: 3, 20: 3, 30: 1}
not the fastest way, but pretty suitable for small lists
UPDATE
or, inspired by inspectorG4dget, this is better:
{x: l.count(x) for x in set(l)}
Related
I have a huge list of over 200.000 of lists inside.
Like this:
huge_list = [
[23, 18, 19, 36, 42],
[22, 18, 19, 36, 39],
[21, 18, 19, 37, 42]
]
It has the following properties:
each number inside each list is unique;
each list has its numbers sorted; // in this case it is not,
JUST for the example purpose.
each number from each list is a random value between 1 and 80;
each list has a predefined size of 20 items. Not less, not more.
numbers are not every time at the same position inside the list. it
can be [1,2,3] or [1, 3, 5] but have in common 1, 3 and (1,3).
I want the result to be how many time each combination can be found along all lists:
18:3(times),
19:3(times),
36:2(times),
(18,42):2(times),
(19,42):2(times),
(18, 36):2(times),
(19, 36):2(times),
(18,19):2(times),
(18,19,36):2(times),
(18, 19, 42):2(times) etc.
The slowest and impossible way is to generate all combinations by 1 taken from 80, then by 2 taken from 80, then by 3 taken from 80 and so on until to the combination by 20 taken by 80 which is almost an infinite number. This is impossible to do but also it is impossible by the number of lists inside the huge_list is over 200.000.
I need something like a Counter but faster. As fast as possible please because it will become a lot slower starting from combos of 12 taken by 80 or even less.
This is what I tried to do until now:
mydict = {}
while len(huge_list) > 1:
to_check = huge_list[0]
del huge_list[0]
for draw in huge_list:
for num in to_check:
# one:
if num in draw:
if num in mydict:
mydict[num] += 1
else:
mydict[num] = 1
if 1 in mydict.values():
for key in mydict.keys():
if mydict[key] == 1:
mydict[key] += 1
print mydict
Result:
{18: 3, 19: 3, 36: 2, 42: 2}
But is almost working for just combinations of 1 taken from 80. How to do it for the other combinations? And how to do it faster than this way?
P.S. I need only combination that they have in common, I am not interested in combinations with 1 or 0 match across all the lists. So, maybe, this could help you in speed it to be even faster.
You could use the powerset algorithm found in more_itertools and put them into a collections.Counter
from more_itertools import powerset
from collections import Counter
from itertools import chain
huge_list = [
[23, 18, 19, 36, 42],
[22, 18, 19, 36, 39],
[21, 18, 19, 37, 42]
]
c = Counter(chain.from_iterable(map(powerset, huge_list)))
print({k if len(k) > 1 else k[0]: v for k, v in c.items() if v > 1 and k})
Results
{18: 3, 19: 3, 36: 2, 42: 2, (18, 19): 3, (18, 36): 2, (18, 42): 2, (19, 36): 2, (19, 42): 2, (18, 19, 36): 2, (18, 19, 42): 2}
This can probably be sped up using pandas although this seems the most efficient way to do this without pandas
P.S: powerset is also a part of the itertools Recipies
Hello I am currently working with a large set of data which contains an even amount of integers, all of which have a matching value. I am trying to create a list which is made up of "one of a pair" in Python.I am able to have multiple pairs of the same value, thus simply using the set function does not work. For example, if I have a list:
List = [10, 10, 11, 20, 15, 20, 15, 11, 10, 10]
In this example, indices 0 and 1 would be a pair, then 2 and 7, 3 and 5, 4 and 6, 8 and 9.
I want to extract from that list the values that make up each pair and create a new list with said values to produce something such as:
newList = [10, 11, 20, 15, 10]
Using the set function makes it such that only one element from the entire set of data is put into the list, where I need half of the total data from List. For situations where I have more than one pair of the same value, it would look something such as:
List = [10, 10, 11, 10, 11, 10]
Would need to produce a list such as:
newList = [10, 11, 10]
Any insight would be great as I am new to Python and there are a lot of functions I may not be aware of.
Thank you
Just try:
new_list = set(list)
This should return your desired output.
If I've understood correctly, you don't want to have any duplicated value, want to retain a list with unique values from a particular list.
If I'm right, a simple way to do so would be:
List = [10, 10, 11, 11, 15, 20, 15, 20]
newList = []
for x in List:
if x not in newList:
newList.append(x)
print(newList)
A python-like way to do so would be:
newList = set(List)
Here is a slight variation on one of #Alain T's answer:
[i for s in [set()] for i in List if (s.remove(i) if i in s else (not s.add(i)))]
NB: the following was my answer before you add the ordering requirement
sorted(List)[::2]
This sorts the input List and then take only one value out of each two consecutive.
As a general approach, this'll do:
l = [10, 10, 11, 20, 15, 20, 15, 11, 10, 10]
i = 0
while i < len(l):
del l[l.index(l[i], i + 1)]
i += 1
It iterates through the list one by one, finding the index of the next occurrence of the current value, and deletes it, shortening the list. This can probably be dressed up in various ways, but is a simple algorithm. Should a number not have a matching pair, this will raise a ValueError.
The following code reates a new list of half the number of items occuring in the input list. The order is in the order of first occurrence in the input list.
>>> from collections import Counter
>>> d = [10, 10, 11, 20, 15, 20, 15, 11, 10, 10]
>>> c = Counter(d)
>>> c
Counter({10: 4, 11: 2, 20: 2, 15: 2})
>>> answer = sum([[key] * (val // 2) for key, val in c.items()], [])
>>> answer
[10, 10, 11, 20, 15]
>>>
If you need to preserve the order of the first occurrence of each pair, you could use a set with an XOR operation on values to alternate between first and second occurrences.
List = [10, 10, 11, 20, 15, 20, 15, 11, 10, 10]
paired = [ i for pairs in [set()] for i in List if pairs.symmetric_difference_update({i}) or i in pairs]
print(p)
# [10, 11, 20, 15, 10]
You could also do this with the accumulate function from itertools:
from itertools import accumulate
paired = [a for a,b in zip(List,accumulate(({n} for n in List),set.__xor__)) if a in b]
print(paired)
# [10, 11, 20, 15, 10]
Or use a bitmap instead of a set (if your values are relatively small positive integers (e.g. between 0 and 64):
paired = [ n for n,m in zip(List,accumulate((1<<n for n in List),int.__xor__)) if (1<<n)&m ]
print(paired)
# [10, 11, 20, 15, 10]
Or you could use a Counter from collections
from collections import Counter
paired = [ i for c in [Counter(List)] for i in List if c.update({i:-1}) or c[i]&1 ]
print(paired)
# [10, 11, 20, 15, 10]
And , if you're not too worried about efficiency, a double sort with a 2 step striding could do it:
paired = [List[i] for i,_ in sorted(sorted(enumerate(List),key=lambda n:n[1])[::2])]
print(paired)
# [10, 11, 20, 15, 10]
So I am trying to create a function where from a list of numbers, it tells me how many pairs of socks there are. Eg. in a list of [10, 20, 20, 10, 10, 30, 50, 10, 20], it tells me there are 3 pairs, because 10x10 and 20x20 and 10x10, with 30, 50 and 20 being left over. But is enough for answer to simply be just '3'!
So this is my code so far, where
n: the number of socks in the pile
ar: the colors of each sock
def sockMerchant(n, ar):
ar = [10, 20, 20, 10, 10, 30, 50, 10, 20]
n = len(ar)
pair = []
for i in ar:
if ar.count >= 2 and (ar.count % 2) == 0:
pair.append(i)
if ar.count < 0:
return False
return (n,ar)
print(len(pair))
However...code not quite there yet. Am i making a mistake in how i call the function? And how is my approach, in first testing whether the number appears at least twice and in even counts, to check for pairs? Please do advise me!
A simple approach would be to count the numbers in a dictionary, and sum the number of pairs found, which must be a multiple of two.
More specifically, you can sum() up the pairs from a collections.Counter() object. Remember that we use // for floor division to round down to the correct number of pairs.
Sample Implementation
from collections import Counter
def sum_pairs(lst):
return sum(v // 2 for v in Counter(lst).values())
Tests
>>> sum_pairs([10, 20, 20, 10, 10, 30, 50, 10, 20, 20])
4
>>> sum_pairs([10, 20, 20, 10, 10, 30, 50, 10, 20, 20, 20])
4
>>> sum_pairs([10, 20, 20, 10, 10, 30, 50, 10, 20])
3
>>> sum_pairs([10, 20, 30, 50])
0
>>> sum_pairs([10, 20, 30, 50, 10])
1
Note: Just for clarity, Counter is a subclass of dict. Its the simplest way to count items from a list.
Hello here is my code in Python :
test = [test[i-1]+3 if i > 0 else 4 for i in range(0, 10)]
My problem is that I want to use a comprehension list for this :
test[0] = 4
test[i] = test[i-1]+3 if i > 0
I want to use a comprehension list to do this.
You don't need any kind of recursion for this. The final list you want is
[4, 7, 10, 13, ...] # 4 + 0, 4 + 3, 4 + 6, 4 + 9, ...
which you can define simply as
test = [4 + 3*i for i in range(10)]
In case you need recursion (in case of a change in formula or conditions), you can use this recursive solution:
from functools import lru_cache
#lru_cache(maxsize=None)
def f(n):
return f(n - 1) + 3 if n > 0 else 4
test = [f(i) for i in range(10)]
print(test)
Output:
[4, 7, 10, 13, 16, 19, 22, 25, 28, 31]
Another version, without recursion, using itertools.accumulate:
from itertools import accumulate
print(list(accumulate(4 if i==0 else 3 for i in range(10))))
Prints:
[4, 7, 10, 13, 16, 19, 22, 25, 28, 31]
Let's say I have a list of:
5 10 10 20 50 50 20
(there are 4 distinguish numbers).
I want to convert them to:
0 1 1 2 3 3 2
(then convert back to the original form).
There are tons of ways to do that, but I am not sure what is the best and Pythonic way?
(a way is to generate a set, convert the set to a list, sort the list, then generate output by the sorted list, but I think it is not the best one)
I think this is a good problem for make use of collections.defaultdict() and itertools.count() methods.
from itertools import count
from collections import defaultdict
c = count()
dct = defaultdict(lambda: next(c))
lst = [5, 10, 10, 20, 50, 50, 20]
conv = [dct[i] for i in lst]
# [0, 1, 1, 2, 3, 3, 2]
back = [k for c in conv for k, v in dct.items() if v == c]
# [5, 10, 10, 20, 50, 50, 20]
The suggested answer by Delgan is O(n^2) due to the nested loops in back. This solution is O(n).
An alternative solution is as follows:
lst = [5, 10, 10, 20, 50, 50, 20]
# Convert (and build reverse mapping)
mapping = {}
reverse_mapping = {}
conv = []
for i in lst:
v = mapping.setdefault(i, len(mapping))
reverse_mapping[v] = i
conv.append(v)
# Convert back
back = [reverse_mapping[v] for v in conv]