Related
I am trying to solve the following problem: a function takes a list A. The results must be a ordered list of list. Each list contains the elements which have the same frequency in the original list A.
Example:
Input: [3, 1, 2, 2, 4]
Output: [[1, 3, 4], [2, 2]]
I managed to sort the initial list A and determine how the frequency of an element.
However, I do not know how to split the original list A based on the frequencies.
My code:
def customSort(arr):
counter = Counter(arr)
y = sorted(arr, key=lambda x: (counter[x], x))
print(y)
x = Counter(arr)
a = sorted(x.values())
print()
customSort([3,1,2,2,4])
My current output:
[1, 3, 4, 2, 2]
[1, 1, 1, 2]
You can use a defaultdict of lists and iterate your Counter:
from collections import defaultdict, Counter
def customSort(arr):
counter = Counter(arr)
dd = defaultdict(list)
for value, count in counter.items():
dd[count].extend([value]*count)
return dd
res = customSort([3,1,2,2,4])
# defaultdict(list, {1: [3, 1, 4], 2: [2, 2]})
This gives additional information, i.e. the key represents how many times the values in the lists are seen. If you require a list of lists, you can simply access values:
res = list(res.values())
# [[3, 1, 4], [2, 2]]
Doing the grunt work suggested by Scott Hunter (Python 3):
#!/usr/bin/env python3
from collections import Counter
def custom_sort(arr):
v = {}
for key, value in sorted(Counter(arr).items()):
v.setdefault(value, []).append(key)
return [v * k for k,v in v.items()]
if __name__ == '__main__':
print(custom_sort([3, 1, 2, 2, 4])) # [[1, 3, 4], [2, 2]]
For Python 2.7 or lower use iteritems() instead of items()
Partially taken from this answer
Having sorted the list as you do:
counter = Counter(x)
y = sorted(x, key=lambda x: (counter[x], x))
#[1, 3, 4, 2, 2]
You could then use itertools.groupby, using the result from Counter(x) in the key argument to create groups according to the counts:
[list(v) for k,v in groupby(y, key = lambda x: counter[x])]
#[[1, 3, 4], [2, 2]]
Find your maximum frequency, and create a list of that many empty lists.
Loop over your values, and add each to the element of the above corresponding to its frequency.
There might be something in Collections that does at least part of the above.
Another variation of the same theme, using a Counter to get the counts and then inserting the elements into the respective position in the result list-of-lists. This retains the original order of the elemens (does not group same elements together) and keeps empty lists for absent counts.
>>> lst = [1,4,2,3,4,3,2,5,4,4]
>>> import collections
>>> counts = collections.Counter(lst)
>>> res = [[] for _ in range(max(counts.values()))]
>>> for x in lst:
... res[counts[x]-1].append(x)
...
>>> res
[[1, 5], [2, 3, 3, 2], [], [4, 4, 4, 4]]
A bit late to the party, but with plain Python:
test = [3, 1, 2, 2, 4]
def my_sort(arr):
count = {}
for x in arr:
if x in count:
count[x] += 1
else:
count[x] = 0
max_frequency = max(count.values()) + 1
res = [[] for i in range(max_frequency)]
for k,v in count.items():
for j in range(v + 1):
res[v].append(k)
return res
print(my_sort(test))
Using only Pythons built-in functions, no imports and a single for loop.
l1= []
l2 = []
def customSort(mylist):
sl = sorted(mylist)
for i in sl:
n = sl.count(i)
if n > 1:
l1.append(i)
if i not in l1:
l2.append(i)
return [l2, l1]
print(customSort([3, 1, 2, 2, 4]))
Output:
[[1, 3, 4], [2, 2]]
I want to multiply each number of list1 with each number of list2.
For example:
[1,2]*[1,2,3] should return something like this: [1,2,3,2,4,6]
I just want to know if there is any special function to calculate this, as it would take a lot of time to calculate this using a for loop.
A simple nested comprehension will work:
lst1, lst2 = [1, 2], [1, 2, 3]
[x * y for x in lst1 for y in lst2]
# [1, 2, 3, 2, 4, 6]
To get all the pairs (the cartesian product) from the two lists, you can also use itertools.product:
from itertools import product
[x * y for x, y in product(lst1, lst2)]
# [1, 2, 3, 2, 4, 6]
You could also do this using dot products, as provided by numpy (I include this as an answer because you said you are looking for any special function, and are looking to optimize speed, though I agree it's not the most readable or straightforward method):
import numpy as np
lst1, lst2 = [1, 2], [1, 2, 3]
np.dot(np.array([lst1]).T, np.array([lst2])).flatten().tolist()
#[1, 2, 3, 2, 4, 6]
try this:
import itertools
a = [1, 2]
b = [1, 2, 3]
result = []
for n in a:
m = map(lambda x,y: x*y, b, itertools.repeat(n))
result.extend(m)
My target is to get a list of consecutive numbers, repeated accordingly with the initial list values. Lets say I have:
initialList=[1,2,3,5]
And I want to get:
targetList=[0,1,1,2,2,2,3,3,3,3,3]
...I'm totally new with Python, sorry for this -probably- very first steps question. Tried many searchs but the results didn't match with my needs, unfortunately. Thank you very much in advance.
The newbie-friendly solution is to use two loops:
result = []
number = 0
for repeat in initialList:
for _ in range(repeat):
result.append(number)
number += 1
print(result) # [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
If you prefer one-liners for whatever reason, you can combine enumerate and range to get
result = [num for num, repeat in enumerate(initialList) for _ in range(repeat)]
IMO, this is a more maintainable functional solution:
initialList = [1, 2, 3, 5]
def listify(x):
return [x]
# create sub-lists [[0], [1], [2], [3], ...]
sublists = map(listify, range(len(initialList)))
# attach to each sub-list the repititions required [([0], 1), ([2], 2), ...]
sublists_with_rep_spec = zip(sublists, initialList)
# create repetitions based on initialList (using list multiplication)
sublists_with_repetitions = starmap(operator.mul, sublists_with_rep_spec)
# flatten everything out
result = chain.from_iterable(sublists_with_repetitions)
print(list(result))
Note that this is all lazy (on python3) so everything will "happen" only when you actually call list.
Here is another way using repeat and chain.from_iterable
from itertools import repeat, chain
list(chain.from_iterable((repeat(idx, num)) for idx, num in enumerate(initialList)))
[0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
You can use enumerate:
initialList=[1,2,3,5]
final_result = [i for b in [[c]*d for c, d in enumerate(initialList)] for i in b]
Output:
[0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
This is possible via itertools, if you wish to remove the need for nested logic. itertools is part of the standard library.
For improving your understanding of Python, I recommend you see #Ajax1234's solution for some nested list comprehensions.
from itertools import chain
initialList = [1,2,3,5]
targetList = list(chain.from_iterable([i]*j for i, j in enumerate(initialList)))
# [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
Note: you can replace [i]*j with itertools.repeat(i, j) or numpy.repeat(i, j) if you use numpy. The former may be preferable as it is lazy.
Very simple solution using sum and enumerate
initialList = [1, 2, 3, 5]
targetList = sum((times*[index] for index, times in enumerate(initialList)), [])
You can try this approach:
data=[[i]*initialList[i] for i,j in enumerate(initialList)]
print([k for i in data for k in i])
Just for fun I tried with lambda :
initialList=[1,2,3,5]
print(list(map(lambda x:[x]*initialList[x],range(0,len(initialList)))))
lambda result is in nested list.
My solution
>>> initialList=[1,2,3,5]
>>> sum(([num]*count for num, count in enumerate(initialList)), [])
[0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
Another easy way:
from functools import reduce
initialList = [1,2,3,5]
targetList = [[index]*item for index, item in enumerate(initialList)]
targetList = reduce(lambda x,y: x+y, targetList)
print(targetList)
# [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
I find most of the current answers either poor performance-wise or hard to read. An alternative functional way of doing this would be by using such itertools functions as chain.from_iterable, repeat, and count:
from itertools import chain, count, repeat
initial_list = [1, 2, 3, 5]
result = list(chain.from_iterable(map(repeat, count(), initial_list)))
# [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
I have a list of list of integers:
ls = [[1,2,3],[2,2,3],[1,1,3]]
and I want to end up with a list that has len(ls[0]) elements, and each element is the element that appears most in that index. In this example the result would be [1 (appears in first&last), 2 (appears in first&second), 3 (appears in all)]
I tried using loops and was hoping for a built-in like all (most?)
ls = [[1,2,3],[2,2,3],[1,1,3]]
ls2=[]
ls2 =[item for sub in ls for item in sub]
ls2
Out[40]: [1, 2, 3, 2, 2, 3, 1, 1, 3]
ls3=[]
for item in len(ls):...
What would be the way to do so?
Transpose your list, apply Counters.
>>> from collections import Counter
>>> ls = [[1,2,3],[2,2,3],[1,1,3]]
>>> counts = [Counter(x) for x in zip(*ls)]
>>> [c.most_common(1)[0][0] for c in counts]
[1, 2, 3]
This will pick an arbitrary number if two numbers share the highest occurence for the same index.
my (alternative solution) 2 cents:
>>> ls = [[1, 2, 3], [2, 2, 3], [1, 1, 3]]
>>> l_mc = [max(x, key=x.count) for x in zip(*ls)]
>>> l_mc
[1, 2, 3]
Here is another way:
from collections import Counter
from operator import itemgetter
ls = [[1, 2, 3], [2, 2, 3], [1, 1, 3]]
print([max(x.items(), key = itemgetter(1))[0] for x in map(Counter, zip(*ls))])
# [1, 2, 3]
What is the best option to retrieve only non-duplicate elements from a Python list? Say I have the following list:
lst = [1, 2, 3, 2, 3, 4]
I would like to retrieve the following:
lst = [1, 4]
(2 and 3 are not unique in that list, so they don't get retrieved)
Use collections.Counter to get counts of items. Combine with a list comprehension to keep only those that have a count of one.
>>> from collections import Counter
>>> lst = [1, 2, 3, 2, 3, 4]
>>> [item for item, count in Counter(lst).items() if count == 1]
[1, 4]
This is a breeze with a list comprehension:
>>> lst = [1, 2, 3, 2, 3, 4]
>>> [x for x in lst if lst.count(x) == 1]
[1, 4]
>>>
Also, I recommend that you do not name a variable list--it overshadows the built-in.