As input I will be getting lists of lists which can up to n-levels and it will vary every time. Suppose, I have a list
[[2, 1, 3], 4, [2, 3], 7, 1, [9, [4, 2], 5]]
here I want to sort this list and expected output is
[1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]]
Here, first sorting is happening based of elements and then based on sum of elements inside list.
code:
input_freq = [[2,1,3],4,[2,3],7,1,[9,[4,2],5]]
res = []
def sortFreq(input_freq):
elements = []
list_of_elements = []
for each in input_freq:
if isinstance(each, list):
print "list"
list_of_elements.append(each)
each.sort()
else:
elements.append(each)
elements.sort()
print elements
print list_of_elements
sortFreq(input_freq)
expected output:
[1, 4, [2, 3], [1, 2, 3], 7, [5, [4, 2], 9]]
but my code returns the wrong result:
[[1, 2, 3], [2, 3], [5, 9, [4, 2]]]
You'll have to work your way down to the nested levels first, then sort the parent levels as the recursive call returns. I'm going to assume you want to return a new list (and not sort in place):
def nested_sort(l):
def sort_key(e):
if isinstance(e, list):
return sum(sort_key(inner) for inner in e)
return e
return sorted(
[nested_sort(e) if isinstance(e, list) else e for e in l],
key=sort_key)
The sort key has to recursively sum nested lists, so this can be kind of expensive if you have many nested levels. In that it may be worth adding a cache based on the identity of the list being summed:
def nested_sort(l, _sum_cache=None):
if _sum_cache is None:
_sum_cache = {}
def sort_key(e):
if isinstance(e, list):
e_id = id(e)
if e_id not in _sum_cache:
_sum_cache[e_id] = sum(sort_key(inner) for inner in e)
return _sum_cache[e_id]
return e
return sorted(
[nested_sort(e, _sum_cache) if isinstance(e, list) else e for e in l],
key=sort_key)
Demo:
>>> nested_sort([[2, 1, 3], 4, [2, 3], 7, 1, [9, [4, 2], 5]])
[1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]]
Here is a solution that has the benefit of doing every sum only once. It is also quite short:
import operator
def sort_lol(lol):
srtd, sums = zip(*sorted((sort_lol(el) if isinstance(el, list) else (el, el)
for el in lol), key=operator.itemgetter(1)))
return list(srtd), sum(sums)
lst = [[2,1,3],4,[2,3],7,1,[9,[4,2],5]]
print(sort_lol(lst))
# ([1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]], 43)
# note that the function returns the sorted list and the total (43 here)
Related
I'm trying to solve this problem here: https://codingbat.com/prob/p252079?parent=/home/peter#norvig.com
In math, a "combination" of a set of things is a subset of the things. We define the function combinations(things, k) to be a list of all the subsets of exactly k elements of things. Conceptually, that's all there is, but there are some questions to settle: (A) how do we represent a subset? (B) What order are the elements within each subset? (C) What order to we list the subsets? Here's what we will agree to: (A) a subset will be a list. (B) The order of elements within a list will be the same as the order within 'things'. So, for example, for combinations([1, 2, 3], 2) one of the subsets will be [1, 2]; whereas [2, 1] is not a subset. (C) The order of subsets will be lexicographical or sorted order -- that is, combinations([1, 2, 3], 2) returns [ [1, 2], [1, 3], 2, 3] ] because [1, 2] < [1, 3] < [2, 3]. You might want to use the function 'sorted' to make sure the results you return are properly ordered.
combinations([1, 2, 3, 4, 5], 2) → [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
combinations([1, 2, 3], 2) → [[1, 2], [1, 3], [2, 3]]
combinations([1, 2, 3, 4, 5, 6], 5) → [[1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 5, 6], [1, 2, 4, 5, 6], [1, 3, 4, 5, 6], [2, 3, 4, 5, 6]]
Here's my code:
def combinations(things, k):
if k == 0 or k == len(things):
return [things]
elif len(things) < k:
return
else:
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for i in range(len(combinations(things[1:], k - 1))):
firstelement = [things[0]]
firstelement += combinations(things[1:], k - 1)[i]
finalcomb.append(firstelement)
for j in range(len(combinations(things[1:], k))):
finalcomb.append(combinations(things[1:], k)[j])
return finalcomb
However, this is the output:
Haven't hit 10 reputation yet so it's a link to the error. I'm not sure what I did wrong, can anybody help me out? Thank you so much.
The problem is this. When k == 0 it shouldn't return [things]. It should return an empty array. Similar to when len(things) < k:. This is because, when k == 0, it means we that we have already found all the numbers for that specific combination.
But there's one more problem. We're returning an empty array. However, in the for loops, we're iterating over the returned array. So if the array is empty, nothing happens. So what we should really return is an empty 2D array. I won't go into too much detail about what the problem is since it's better for you to try and understand why it's not working. Try adding print statements inside and outside the for loops.
Anyway, the working code looks like this:
def combinations(things, k):
if k == len(things):
return [things[:]]
if len(things) < k or k == 0:
return [[]]
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for comb in subcomb1:
firstelement = [things[0]]
firstelement += comb
finalcomb.append(firstelement)
finalcomb += subcomb2
return finalcomb
Note a few things:
Use the variables you've already assigned (I'm assuming you forgot about them)
Lists can be concatenated using +, similar to strings. If you return within an if statement, you don't need an else for the next line since if the if statement is satisfied, it would definitely not go to the else.
You simply can try using itertools:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 2):
output.append(list(nums))
print(output)
output:
[[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
For 3 nums:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 3):
output.append(list(nums))
print(output)
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]]
The problem is as follows: Write a function choose_gen(S, k) that produces a generator that yields all the k-element subsets of a set S (represented as a sorted list of values without duplicates) in some arbitrary order.
Here is what I have so far:
def choose_gen(l: object, k: object) -> object:
if k>len(l):
return None
elif k == len(l):
yield sorted(l)
return
for i in l:
aux = l[:]
aux.remove(i)
result = choose_gen(aux, k)
if result:
yield from result
It runs but does not avoid the duplicate subsets. Could somebody please help to solve this issue? Thanks in advance.
an example of an input would be:
print([s for s in choose_gen([1,3,5,7], 2)])
actual output: [[5, 7], [3, 7], [3, 5], [5, 7], [1, 7], [1, 5], [3, 7], [1, 7], [1, 3], [3, 5], [1, 5], [1, 3]]
expected output: [[5, 7], [3, 7], [3, 5], [1, 7], [1, 5], [1, 3]]
I am not sure. But
I think that in the 6th line you have to write something after return. You have left it empty.
Or try,
new_menu = [s for s in choose_gen([1,3,5,7], (2)]
final_new_menu = list(dict.fromkeys(new_menu))
print(final_new_menu)
I have a list of dataframes with data duplicating in every next dataframe within list which I need to subtract between themselves
the_list[0] = [1, 2, 3]
the_list[1] = [1, 2, 3, 4, 5, 6, 7]
There are also df headers. Dataframes are only different in number of rows.
Wanted solution:
the_list[0] = [1, 2, 3]
the_list[1] = [4, 5, 6, 7]
Due to the fact that my list of lists, the_list, contains several dataframes, I have to work backward and go from the last df to first with first remaining intact.
My current code (estwin is the_list):
estwin = [df1, df2, df3, df4]
output=([])
estwin.reverse()
for i in range(len(estwin) -1):
difference = Diff(estwin[i], estwin[i+1])
output.append(difference)
return(output)
def Diff(li_bigger, li_smaller):
c = [x for x in li_bigger if x not in li_smaller]
return (c)
Currently, the result is an empty list. I need an updated the_list that contains only the differences (no duplicate values between lists).
You should not need to go backward for this problem, it is easier to keep track of what you have already seen going forward.
Keep a set that gets updated with new items as you traverse through each list, and use it to filter out the items that should be present in the output.
list1 = [1,2,3]
list2 = [1,2,3,4,5,6,7]
estwin = [list1, list2]
lookup = set() #to check which items/numbers have already been seen.
output = []
for lst in estwin:
updated_lst = [i for i in lst if i not in lookup] #only new items present
lookup.update(updated_lst)
output.append(updated_lst)
print(output) #[[1, 2, 3], [4, 5, 6, 7]]
Your code is not runnable, but if I guess what you meant to write, it works, except that you have one bug in your algorithm:
the_list = [
[1, 2, 3],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
]
def process(lists):
output = []
lists.reverse()
for i in range(len(lists)-1):
difference = diff(lists[i], lists[i+1])
output.append(difference)
# BUGFIX: Always add first list (now last becuase of reverse)
output.append(lists[-1])
output.reverse()
return output
def diff(li_bigger, li_smaller):
return [x for x in li_bigger if x not in li_smaller]
print(the_list)
print(process(the_list))
Output:
[[1, 2, 3], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
[[1, 2, 3], [4, 5, 6, 7], [8, 9]]
One-liner:
from itertools import chain
l = [[1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
new_l = [sorted(list(set(v).difference(chain.from_iterable(l[:num]))))
for num, v in enumerate(l)]
print(new_l)
# [[1, 2], [3], [4], [5]]
Im trying to figure out how to take a list of lists of integers and create a new list that contains combinations from the list of lists. I want the combination to start with a value from the first list and then respectively take 1 from each of the subsequent lists, only if the value is greater than the previous list.
l=[[1,2,3],[4,8],[5,10]]
# the answer would look like this
correct=[[1,4,5],[1,4,10],[1,8,10],[2,4,5],[2,4,10],[2,8,10],[3,4,5],[3,4,10],[3,8,10]]
>>> from itertools import product
...
...
... def combos(lst):
... result = []
... for p in product(*lst):
... if all(a < b for a, b in zip(p, p[1:])):
... result.append(list(p))
... return result
...
>>> lst = [[1, 2, 3], [4, 8], [5, 10]]
>>> correct = [[1, 4, 5], [1, 4, 10], [1, 8, 10], [2, 4, 5], [2, 4, 10],
... [2, 8, 10], [3, 4, 5], [3, 4, 10], [3, 8, 10]]
>>> combos(lst) == correct
True
List comprehension is probably a great way to go. It works nicely because of your constraints. You probably want something like:
[[i,j,k] for i in l[0] for j in l[1] if j>i for k in l[2] if k>j]
>>> [[1, 4, 5],
[1, 4, 10],
[1, 8, 10],
[2, 4, 5],
[2, 4, 10],
[2, 8, 10],
[3, 4, 5],
[3, 4, 10],
[3, 8, 10]]
This makes a list of lists of the form [i,j,k] for all the i's in l[0] for all the j's in l[1] if j>i and for all the k's in l[2] if k>j (since we already know that j>i at this point)
However, the code above only works for an input list of list of length 3. Took me a little bit, but this recursive approach should work for a input list of any length
def list_of_lists(in_list):
full_list=[]
def recurse(so_far, l):
if l==len(in_list):
return so_far
next_list = in_list[l]
for i in next_list:
if i>so_far[-1]:
new_list = recurse(so_far.copy()+[i], l+1)
if new_list:
full_list.append(new_list)
for i in in_list[0]:
recurse([i],1)
return full_list
l=[[1,2,3],
[4,8],
[5,10]]
ansList = []
for i in range(len(l[0])):
for j in range(len(l[1])):
for k in range(len(l[2])):
if l[0][i]<l[1][j] and l[1][j]<l[2][k]:
ansList.append([l[0][i],l[1][j],l[2][k]])
print(ansList)
I have the following list
list = [1, 2, 3, [3, [1, 2]]]
the result would be:
[[[2, 1], 3], 3, 2, 1]
How to sort that list by size of list and by element?
Here's one way to recursively sort the list:
def recursive_sort(item):
if isinstance(item, list):
item[:] = sorted(item, key=recursive_sort)
return 0, -len(item)
else:
return 1, -item
lst = [1, 2, 3, [3, [1, 2], [2, 3, 6]]]
print(sorted(lst, key=recursive_sort))
# [[[6, 3, 2], [2, 1], 3], 3, 2, 1]
Caveat: This is more of an academic exercise and should never be used in production code. The state of the list during a sort (at least with Timsort in CPython) is undefined, so you shouldn't count on this to always work.