I have a list of lists:
[[1, 0], [2, 1], [5, 4], [1, 3], [4, 1], [3, 2], [0, <NA>]]
The list having <NA> as second element will always be the first list in nested list.
In the two subsequent lists, the first element of first list should match with second element of second list. e.g.: [0, <NA>], [1, 0], [2, 1]
The resultant list should cover all the elements from original list.
Expected output:
[[0, <NA>], [1, 0], [2, 1], [3, 2], [1, 3], [4, 1], [5, 4]]
Here, after [1, 0], we could have gone to [4, 1] as well; but that would be wrong since we won't be able to cover all the elements in the original list. I am using Python as programming language here. Any help would be appreciated. Please and thanks.
(Swapping your <NA> for a None) this looks for the longest path through the list that visits all elements exactly once.
def sort_path(elements):
def f(prefix, seq):
# get the current element to match
curr = prefix[-1][0] if len(prefix) > 0 else None
# get possible next nodes in path
next = [x for x in seq if x[1] == curr]
# get candidate paths from each next node
candidates = [f(prefix + [n], [x for x in seq if x != n]) for n in next]
# return the longest path from the candidates (or the prefix if no candidates)
return prefix if len(candidates) == 0 else max(candidates, key=len)
result = f([], elements)
return result if len(result) == len(elements) else None
input = [[1, 0], [2, 1], [5, 4], [1, 3], [4, 1], [3, 2], [0, None]]
print(sort_path(input))
# gives: [[0, None], [1, 0], [2, 1], [3, 2], [1, 3], [4, 1], [5, 4]]
This code produces your expected output using recursion.
your_list = [[1, 0], [2, 1], [5, 4], [1, 3], [4, 1], [3, 2], [0, '<NA>']]
first_item = [x for x in your_list if x[1] == '<NA>'][0] # Assuming only one of '<NA>' exists
remaining_list = your_list.copy()
remaining_list.remove(first_item)
def get_custom_order(remaining_list, ordered_list):
work_copy = remaining_list.copy()
start_value = ordered_list[-1][0]
for item in remaining_list:
if item[1] == start_value:
ordered_list.append(item)
work_copy.remove(item)
get_custom_order(work_copy, ordered_list)
break
return ordered_list
ordered_list = get_custom_order(remaining_list, [first_item])
print(ordered_list)
However, my answer is incomplete. This code only works because of the sorting of your list. It does not fulfill your requirement to cover sorting of all elements. I'll try to fix that and update my answer.
Related
For a given N, I have a list of all numbers from 0 to N-1
A = list(range(0,N));
and I want to find a list of all possible decompositions into lists of sizes two or higher, without repetitions. For example, for N=4 I have
A = [0,1,2,3];
and the output I want is
OUT = [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]];
Up to N=5, the decomposition of the initial list into only two pieces (of length 2 and 3) makes the problem very easy. However, I can't find a way to do it for higher N, since the lists of length four must be further split into two lists of length 2.
Does anyone have any suggestions on how to solve this? I feel there must be a straightforward recursive trick to do this, but I have been trying for a day now, and I am a little stuck!
Thanks!
PS: the results for N smaller than 6 are:
N=1) OUT = [[[0]]];
N=2) OUT = [[[0, 1]]];
N=3) OUT = [[[0, 1, 2]]];
N=4) OUT = [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]];
N=5) OUT = [[[0, 1, 2, 3, 4]], [[0, 1], [2, 3, 4]], [[0, 2], [1, 3, 4]], [[0, 3], [1, 2, 4]], [[0, 4], [1, 2, 3]], [[1, 2], [0, 3, 4]], [[1, 3], [0, 2, 4]], [[1, 4], [0, 2, 3]], [[2, 3], [0, 1, 4]], [[2, 4], [0, 1, 3]], [[3, 4], [0, 1, 2]]];
PPS: I am a physicist and haven't been programming for a while; the code probably looks terrible, and the problem might be very easy... sorry for that!
Consider the last item i.e N-1, suppose we have two sets of combinations. one for list(range(0,N-1)) and one for list(range(0,N-2)). Now, if you want to put the last item in these combinations, you should have a different approach for each one of them, which I've explained below:
Combinations of list(range(0, N-1)): To put the last item in these combinations, you have no choice other than to put it in one of the sets that are already available to understand this better consider that you have all combinations for four and now you want to add 5 to this combination. So you have :
[[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]]
Adding last item( i.e 4) to these combination would get us something like bellow:
[[[0, 1, 2, 3, 4]], [[0, 1, 4], [2, 3]], [[0, 1], [2, 3, 4]], [[0, 2, 4], [1, 3]], [[0, 2], [1, 3, 4]], [[0, 3, 4], [1, 2]], [[0, 3], [1, 2, 4]]]
We put 4 in every combination and make new combinations out of them. So for this part, we need a recursive call for N-1. As you can see in this situation, each sets that N-1 is in has at least three items. That's because we expanded our set, which already existed and had at least two items.
Combinations of N-2 items: I've considered this for when N-1 is in a set with only two items. To find these combinations, we need to select one of the rest N-1 items and consider that selected item with item N-1 as one set and find every other combination for the rest of N-2 items. To give you an example again, consider N = 5 so the last item is 4. If we want to pair the last item with 3, we could build all combinations for (0, 1, 2) and put pair of the (3, 4) to the mix. It would be something like this for N=5:
[[[0 , 1 , 2] , [3 , 4]] , [[0 , 1 , 3] , [2 , 4]] , [[0 , 2 , 3] , [1 , 4]] , [[ 1 , 2 , 3] , [0 , 4]]]
I've implemented this using recursive functions in python. I'm not a python developer, so there may be some enhancements in implementations, but the algorithm is working fine:
import copy
def recursive_builder(arr):
if len(arr) == 3:
return [[[arr[0], arr[1], arr[2]]]]
if len(arr) == 4:
return [[[arr[0], arr[1], arr[2], arr[3]]], [[arr[0], arr[1]], [arr[2], arr[3]]], [[arr[0], arr[2]], [arr[1], arr[3]]], [[arr[0], arr[3]], [arr[1], arr[2]]]]
temp_array = arr[0:len(arr)-1]
recursive_builder_one_step_before = recursive_builder(temp_array)
new_from_one_step_before = []
last_item = arr[len(arr)-1]
for item in recursive_builder_one_step_before:
for i in range(0 , len(item)):
temp_item = copy.deepcopy(item)
temp_item[i].append(last_item)
new_from_one_step_before.append(temp_item)
new_from_two_step_before = []
for i in range(0 , len(temp_array)):
new_arr = temp_array[:i] + temp_array[i+1 :]
recursive_builder_two_step_before = recursive_builder(new_arr)
new_from_two_step_before_inner = []
for item in recursive_builder_two_step_before:
new_item = item + [[temp_array[i] , last_item]]
new_from_two_step_before_inner.append(new_item)
new_from_two_step_before = new_from_two_step_before + new_from_two_step_before_inner
return new_from_two_step_before + new_from_one_step_before
N=6
recursive_builder(list(range(0,N)))
You could run this code on Colab
Edit: I've added memorization to improve the performance a little bit, but my build_from_memory is not O(1), so the improvement could be much better if I could improve the performance of that function.
memotization_dict = {3 : [[[0, 1, 2]]] , 4 : [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]] }
def build_from_memory(arr):
memory = memotization_dict[len(arr)]
ret_val = []
for item in memory:
l2 = []
for i in item:
l1 = []
for j in i:
l1.append(arr[j])
l2.append(l1)
ret_val.append(l2)
return ret_val
def recursive_builder(arr):
if len(arr) in memotization_dict:
return build_from_memory(arr)
temp_array = arr[0:len(arr)-1]
recursive_builder_one_step_before = recursive_builder(temp_array)
new_from_one_step_before = []
last_item = arr[len(arr)-1]
for item in recursive_builder_one_step_before:
for i in range(0 , len(item)):
temp_item = copy.deepcopy(item)
temp_item[i].append(last_item)
new_from_one_step_before.append(temp_item)
new_from_two_step_before = []
for i in range(0 , len(temp_array)):
new_arr = temp_array[:i] + temp_array[i+1 :]
recursive_builder_two_step_before = recursive_builder(new_arr)
new_from_two_step_before_inner = []
for item in recursive_builder_two_step_before:
new_item = item + [[temp_array[i] , last_item]]
new_from_two_step_before_inner.append(new_item)
new_from_two_step_before = new_from_two_step_before + new_from_two_step_before_inner
if(arr == list(range(0 , len(arr)))):
memotization_dict[len(arr)] = new_from_two_step_before + new_from_one_step_before
return new_from_two_step_before + new_from_one_step_before
Please could I have help with the following query in Python 3.9.
I have the following sublists:
[0, 1]
[1, 3]
[2, 5]
I would like to make a new list with each of these sublists repeated a different number of times. Required output:
[[0,1],[0,1],[0,1],[1,3],[1,3],[2,5],[2,5],[2,5],[2,5]]
I have tried doing the following:
[[[0,1]]*3,[[1,3]]*2,[[2,5]]*4]
However I get this:
[[[0,1],[0,1],[0,1]],[[1,3],[1,3]],[[2,5],[2,5],[2,5],[2,5]]]
How do I get my desired output? Or alternatively, how do I just flatten it by one level? Thank you
You can just unpack the sublists:
[*[[0,1]]*3, *[[1,3]]*2, *[[2,5]]*4]
# [[0, 1], [0, 1], [0, 1], [1, 3], [1, 3], [2, 5], [2, 5], [2, 5], [2, 5]]
Note however, that the resulting sublists are not independent, but references to the same list objects (changes made to one sublist will be reflected in all the equal others)! Better use generators/comprehensions:
[*([0,1] for _ in range(3)),
*([1,3] for _ in range(2)),
*([2,5] for _ in range(4))]
# [[0, 1], [0, 1], [0, 1], [1, 3], [1, 3], [2, 5], [2, 5], [2, 5], [2, 5]]
The more general question of 1-level flattening has been asked and answered multiple times, but the main options are the nested comprehension:
[x for sub in lst for x in sub]
or itertools.chain:
[*chain(lst)]
You can use list loop:
r1 = [0, 1]
r2 = [1, 3]
r3 = [2, 5]
h = [*(r1 for x in range(3)),
*(r2 for x in range(2)),
*(r3 for x in range(4))]
print(h)
This question already has answers here:
Does Python make a copy of objects on assignment?
(5 answers)
Closed 1 year ago.
I wanted to build a function that finds all the possible subsets of a set.
The first function works well, while the second doesn't. In the first I used a list comprehension to remove the first element of a list, while in the second I used pop(0). Why do they output different results?
The first function is:
def combinations(n):
if len(n) == 1:
return [[], n]
a = [element for element in n if element != n[0]]
return [[n[0]] + comb for comb in combinations(a)] + combinations(a)
The second function is:
def combinations(n):
if len(n) == 1:
return [[], n]
a = n
a.pop(0)
return [[n[0]] + comb for comb in combinations(a)] + combinations(a)
The output of the first is:
[[0, 1, 2], [0, 1, 2, 3], [0, 1], [0, 1, 3], [0, 2], [0, 2, 3], [0], [0, 3], [1, 2], [1, 2, 3], [1], [1, 3], [2], [2, 3], [], [3]]
The output of the second is:
[[3, 3, 3], [3, 3, 3, 3], [3, 3], [3, 3, 3], [3], [3, 3], [], [3]]
Already answered in the comments. In addition, this should solve the problem.
def combinations(n):
if len(n) == 1:
return [[], n]
a = list(n)
a.pop(0)
return [[n[0]] + comb for comb in combinations(a)] + combinations(a)
everyone!
I have this dictionary which contains name of files as keys and some data as values.
In the name of the file there is some float number, which indicates if the test that was done on this data was on positive or negative of some field.
I want to separate this dictionary into two lists, eg: positive and negative. These two list corresponds to the float values of the name of the files containing positive and negative
The following code separated the values according to the float number. But return 3D list.
Question How can I use list comprehension to have a 2D list as a result in this case?
mainDictlist = [{'A1_0.5.txt':[[4,4,4],[4,4,4]],'B1_-0.5.txt':[[1,2,3],[1,2,3]],'A2_0.5.txt'[[2,2,2],[2,2,2]],'B2_-0.5.txt':[[1,1,1],[1,1,1]]}]
def findfloat(keys):
lst_numberStr = re.findall(r'[*+-]?\d+\.\d+', keys)
v = float(lst_numberStr[0])
return v
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
findFloat = findfloat(k)
if findFloat > 0:
positive.append(item[k])
if findFloat < 0:
negative.append(item[k])
print('List Pos',positive)
print('List Neg',negative)
Returns
>>>List Pos [[[4, 4, 4], [4, 4, 4]], [[2, 2, 2], [2, 2, 2]]]
>>>List Neg [[[1, 2, 3], [1, 2, 3]], [[1, 1, 1], [1, 1, 1]]]
Desired Return
List Pos [[4, 4, 4], [4, 4, 4]], [[2, 2, 2], [2, 2, 2]]
List Neg [[1, 2, 3], [1, 2, 3]], [[1, 1, 1], [1, 1, 1]]
Use list.extend
Ex:
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
findFloat = findfloat(k)
if findFloat > 0:
positive.extend(item[k])
if findFloat < 0:
negative.extend(item[k])
print('List Pos',positive)
print('List Neg',negative)
Output:
List Pos [[4, 4, 4], [4, 4, 4], [2, 2, 2], [2, 2, 2]]
List Neg [[1, 2, 3], [1, 2, 3], [1, 1, 1], [1, 1, 1]]
Your example of desired return is not a 2D list, but two separate lists.
In order to get a 2D list like [[4, 4, 4], [4, 4, 4], [2, 2, 2], [2, 2, 2]] you can replace positive.append(item[k]) with positive += v and do the same for negative.
Also, judging from the example you provided, filenames with positive floats doesn't contain - while those with negative do. So, separation of values can be done this way:
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
if "-" in k:
negative += v
else:
positive += v
Hope this helps.
I am trying to write a program in python which should sort a list within a list.
Examples -
List before sorting: [[2, 1], [2, 2], [3, 3], [3, 1], [1, 1], [1, 2]]
List after sorting: [[1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [3, 3]]
List before sorting: [[3, 3], [2, 2], [1, 2], [2, 1], [3, 1], [1, 1]]
List after sorting: [[1, 1], [2, 1], [1, 2], [2, 2], [3, 1], [3, 3]]
List before sorting: [[1, 1], [3, 3], [2, 1], [2, 2], [1, 2], [3, 1]]
List after sorting: [[1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [3, 3]]
My code:
import math
def combsort(list1):
gap = len(list1)
shrink = 1.3
sorted = False
while sorted == False:
gap = gap/shrink
if gap > 1:
sorted = False
else:
gap = 1
sorted = True
i = 0
while i + gap < gap:
distance1 = math.sqrt(list1[i[0]]**2 + list1[i[1]]**2)
distance2 = math.sqrt(list1[i+gap[0]]**2 + list1[i+gap[1]]**2)
if distance1 > distance2:
temporary = list1[i]
list1[i] = list1[i + gap]
temporary = list1[i + gap]
sorted = False
i = i + 1
list1 = [[2, 1], [2, 2], [3, 3], [3, 1], [1, 1], [1, 2]]
combsort(list1)
print(list1)
My code doesn't work and prints out the exact same list. Any help?
This is what I was given to follow:
Comb sort is a variation of bubble sort that generally performs more efficient sorting. It accomplishes this by moving low values near the end of the list further toward the front of the list than bubble sort would during early iterations.
implement a function called combsort that does the following:
Takes as input a 2D list that contains information representing x/y points in 2D space. Each item in the list will be a list with 2
items an x and a y coordinate. For example, the list could be [ [0,
1],[2, 1], [3, 3], [1, 1], … ]
List item Performs an in-place sort (i.e., does not create a new list, but modifies the original) using the comb sort algorithm that
sorts the 2D list such that points with lower 2 Euclidean distance to
the origin (0, 0) appear earlier in the list. In this case, you are
comparing distances instead of directly comparing list values – it may
be useful to implement and use a distance calculation function. Note –
the Euclidean distance of a point (x, y) from the origin (0, 0) can be
calculated with the following equation: distance(x,y) = �! + �!
Does not return a value. As the input list is sorted in place, it will be modified directly and these modifications will be reflected
outside the function, so a return value is not needed.
The while loop never gets executed because its condition cannot be true:
while i + gap < gap:
Hint: use more print statements or a debugger to check the values of things while the program is running.
The error is in your while statement, it should be:
while i + gap < len(list1):
as shown in the pseudocode here. Currently the while loop is never even entered... which hides your other problems (see below).
You are indexing into a 2-D list wrong:
list1[i[0]] #get first item in list `i` and use that number to index into list1
list1[i][0] #get the ith sublist in list1 and get its first item
You need to make sure you use integers for your list indices:
gap = int(gap/shrink)
And for the grand finale....you swapped the order of your assignment, ruining your swap logic
temporary = list1[i + gap] #wrong
list1[i + gap] = temporary #should be this
You can also do this without the use of temporary in Python:
list1[i+gap], list1[i] = list1[i], list1[i+gap]
After all these changes, the code works as expected:
>>>combsort([[3, 3], [2, 2], [1, 2], [2, 1], [3, 1], [1, 1]])
[[1, 1], [2, 1], [1, 2], [2, 2], [3, 1], [3, 3]]