Related
I have a series of lists, and I want to combine them in a larger nested list. However, I want to order them in a certain way. I want the first sub-list to be the one whose first element is zero. Then i want the second sub-list to be the one whose first element is the same as the LAST element of the previous list.
For example, here's four sub-lists;
[0, 3], [7, 0], [3, 8], [8, 7]
I want to end up with this;
[[0, 3], [3, 8], [8, 7], [7,0]]
I can't for the life of me see the code logic in my head that would achieve this for me.
Can anyone help please?
UPDATE
Solved!
Many thanks to all who contributed!
I think of your list as being a collection of links which are to be arranged into a chain. Here is an approach which uses #quanrama 's idea of a dictionary keyed by the first element of that link:
links = [[0, 3], [7, 0], [3, 8], [8, 7]]
d = {link[0]:link for link in links}
chain = []
i = min(d)
while d:
link = d[i]
chain.append(link)
del d[i]
i = link[1]
print(chain) #[[0, 3], [3, 8], [8, 7], [7, 0]]
Another approach with a generator function:
links = [[0, 3], [7, 0], [3, 8], [8, 7]]
def get_path(links, *, start=0, end=0):
linkmap = dict(links)
key = start
while True:
link = linkmap[key]
yield [key,link]
key = link
if link == end:
break
print(list(get_path(links)))
print(list(get_path(links,start=3,end=3)))
# [[0, 3], [3, 8], [8, 7], [7, 0]]
# [[3, 8], [8, 7], [7, 0], [0, 3]]
You can try something like this:
source = [[0, 3], [7, 0], [3, 8], [8, 7]]
# Start at 0
last_val = 0
# this will be the output
l = []
while len(l)==0 or last_val!=0:
# Find the first value where the first element is last_val
l.append(next(i for i in source if i[0]==last_val))
# set last val to the second element of the list
last_val = l[-1][1]
print(l)
like extremely new, so please bear with me.
Im trying to increment each element of a nested list by 1
a straight forward list works fine:
a = [1,2,3,4,5,6,7,8]
for i in range(len(a)):
a[i] += 1
but why doesn't it work with:
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
what am i missing?
Let's unroll the loop so we can inspect:
a = [1, 2, 3, 4, 5, 6, 7, 8]
i = 0
assert a[i] == 1 # the zeroeth element of a
a[i] += 1 # increment 1, making it 2
assert a[i] == 2
i = 1
# ... etc, repeat
contrast with
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
i = 0
assert a[i] == [1, 2] # the zeroeth element of a is now the list [1, 2]!
a[i] += 1 # TypeError! What's the logical equivalent of adding 1 to a list? There isn't one
It won't work as you have another list inside list a or nested list. Therefore, you need nested loop:
Following program would help:
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
for i in range(len(a)):
for j in range(len(a[i])):
a[i][j] += 1
Hope it Helps!!!
In the first iteration your a[i] += 1 would effectively be a[0] = [1, 2] + 1. That doesn't exactly make sense. You need to have a second, inner loop.
Use nested for loops:
for i in range(len(a)):
for ii in range(len(a[i])):
a[i][ii] += 1
Because you have nested list then you have to iterate that nested one again
Here a cool way to check if there list inside with recursion
a = [1,[2, 4],3,[4, 5],5,6,7,8]
def increment_a_list(some_list):
for i in range(len(some_list)):
if type(some_list[i]) is list: # if the element is a list then execute the function again with that element
increment_a_list(some_list[i])
else:
some_list[i] += 1 # +1 to that element if it not a list
return some_list
print(increment_a_list(a))
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
Each item in the list is again a list. You need to traverse and incerement each of it individually. So, nested for loop can solve your problem.
A more generic solution - Recursion
### Using recursion - The level of nesting doesn't matter
def incrementor(arr):
for i in range(len(arr)):
if type(arr[i]) is list:
incrementor(arr[i])
else:
arr[i] = arr[i] + 1
a = [[1, 2], [3, 4], [5, 6], [7, 8],9,10,11,12,[13,[14,15,16]],[[17,18],[19,[20,21]]]]
incrementor(a)
print(a)
Output
[[2, 3], [4, 5], [6, 7], [8, 9], 10, 11, 12, 13, [14, [15, 16, 17]], [[18, 19], [20, [21, 22]]]]
Given an array of numbers (e.g. [3, 5, 2]), I'm trying to generate a list of possible arrays that result from adding 1 to one entry in the array: [[4, 5, 2], [3, 6, 2], [3, 5, 3]].
I can get it done by the following, but wondering if there's a more pythonic way to get the result?
test = [3, 5, 2]
result = [t.copy() for _ in range(len(test))]
for index, _ in enumerate(result):
result[index][index] += 1
Here's how to do it with a list comprehension:
test = [3, 5, 2]
print [test[:i] + [v + 1] + test[i+1:] for i,v in enumerate(test)]
output
[[4, 5, 2], [3, 6, 2], [3, 5, 3]]
Here is another inline solution with list comprehension:
test = [3, 5, 2]
result = [[v+1 if i==j else v for j, v in enumerate(test)] for i in range(len(test))]
or, as noticed by PM 2Ring, you can exploit the fact that True == 1 and False == 0:
result = [[v + (i==j) for j, v in enumerate(test)] for i in range(len(test))]
I have a list like [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]. How can I get a list that contains lists of all the lists that contain overlapping elements added together? For the example input, the result should be [[1, 2, 4, 5], [0, 3, 6, 7, 8, 12], [14, 18]].
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
result = []
for s in a:
s = set(s)
for t in result:
if t & s:
t.update(s)
break
else:
result.append(s)
This will go one-by-one through the list and create a set from the current sublist (s). Then it will check in the results, if there is another set t that has a non-empty intersection with it. If that’s the case, the items from s are added to that set t. If there is no t with a non-empty intersection, then s is a new independent result and can be appended to the result list.
A problem like this is also a good example for a fixed-point iteration. In this case, you would look at the list and continue to merge sublists as long as you could still find lists that overlap. You could implement this using itertools.combinations to look at pairs of sublists:
result = [set(x) for x in a] # start with the original list of sets
fixedPoint = False # whether we found a fixed point
while not fixedPoint:
fixedPoint = True
for x, y in combinations(result, 2): # search all pairs …
if x & y: # … for a non-empty intersection
x.update(y)
result.remove(y)
# since we have changed the result, we haven’t found the fixed point
fixedPoint = False
# abort this iteration
break
One way I can think of doing this is through recursion. Start with one item, then loop until you find every number it's connected to. For each of these numbers, you must do the same. Hence the recursion. To make it more efficient, store numbers you've visited in a list and check it at the beginning of each recursive sequence to make sure you don't repeat any explorations.
A two liner:
a_set = [set(x) for x in a]
result = [list(x.union(y)) for i,x in enumerate(a_set) for y in a_set[i:]
if x.intersection(y) and x != y]
I have left the last step for you:
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
result = [[1, 2, 4, 5], [0, 3, 6, 7, 8, 12], [14, 18]]
# each sub list
result2 = []
count = 0
print a
for sub_list in a:
print count
print "sub_list: " + str(sub_list)
a.pop(count)
print "a: " + str(a)
#each int
sub_list_extend_flag = False
for int_in_sub_list in sub_list:
print "int_in_sub_list: " + str(int_in_sub_list)
for other_sub_list in a:
print "current_other_sub_list: " + str(other_sub_list)
if int_in_sub_list in other_sub_list:
sub_list_extend_flag = True
other_sub_list.extend(sub_list)
result2.append(list(set(other_sub_list)))
if not sub_list_extend_flag:
result2.append(sub_list)
count += 1
print result2
Simple answer:
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
print y
its more simple than first one:
box=[]
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
box.append(y)
print box
Result:[1, 2, 4, 2, 5, 0, 3, 7, 8, 12, 3, 6, 18, 14]
And with this, you can compare the numbers:
box=[]
box2=""
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
box.append(y)
print box
for a in box:
box2+=str(a)
print box2
Result: 12425037812361814
Also you can make it more cute:
print " ".join(box2)
Result: 1 2 4 2 5 0 3 7 8 1 2 3 6 1 8 1 4
I have a problem with "pairing" arrays into one (by index). Here is an example:
INPUT:
inputArray = [[0, 1, 2, 3, 4], [2, 3, 5, 7, 8], [9, 6, 1]]
EXPECTED OUTPUT:
outputArray =
[[0,2,9],
[1,3,6],
[2,5,1],
[3,7,chooseRandom()],
[4,8,chooseRandom()]]
Questions:
How to avoid "out of range" "index error" problem
How to write chooseRandom() to choose N neighbour
Answers:
[SOLVED] Solutions provided by #jonrsharpe & #Christian & #Decency works as
expected
Clarification:
By N neighbour I mean:
I'm using python but feel free to share your thoughts in any language.
I think the following will do what you want:
from itertools import izip_longest # 'zip_longest' in Python 3.x
from random import choice
# Step 1
outputArray = list(map(list, izip_longest(*inputArray)))
# Step 2
for index, arr in enumerate(outputArray):
if any(item is None for item in arr):
valid = [item for item in arr if item is not None]
outputArray[index] = [choice(valid) if item is None else item
for item in arr]
This has two steps:
Combine all sub-lists of inputArray to the length of the longest sub-array, filling with None: [[0, 2, 9], [1, 3, 6], [2, 5, 1], [3, 7, None], [4, 8, None]]; and
Work through the outputArray, finding any sub-lists that contain None and replacing the None with a random choice from the other items in the sub-list that aren't None.
Example output:
[[0, 2, 9], [1, 3, 6], [2, 5, 1], [3, 7, 3], [4, 8, 8]]
Here's my approach to the problem, in Python 3.4. I don't really know what you mean by "choose N neighbour" but it should be pretty easy to write that however you'd like in the context below.
inputArray = [[0, 1, 2, 3, 4], [2, 3, 5, 7, 8], [9, 6, 1]]
import itertools
zipped = itertools.zip_longest(*inputArray, fillvalue=None)
outputArray = [list(item) for item in zipped]
# [[0, 2, 9], [1, 3, 6], [2, 5, 1], [3, 7, None], [4, 8, None]]
# Now replace the sentinel None in our sublists
for sublist in outputArray:
for i, element in enumerate(sublist):
if element is None:
sublist[i] = chooseRandom()
print(outputArray)
Not the most pythonic way, but you could try using this code snipped, read the comments in the code below:
import itertools, random
inputArray = [ [0, 1, 2, 3, 4], [2, 3, 5, 7, 8], [9, 6, 1] ]
outputArray = []
max_length = max(len(e) for e in inputArray) # maximum length of the sublists in <inputArray>
i = 0 # to keep the index of sublists of <outputArray>
for j in range(max_length):
outputArray.append([]) # add new sublist
for e in inputArray: # iterate through each element of <inputArray>
try:
outputArray[i].append(e[j]) # try to append the number, if an exception is raised
# then the code in the <except> clause will be executed
except IndexError as e:
outputArray[i].append(random.randint(0, 10)) # add the random number
i += 1 # increase the sublists index on each iteration
print outputArray
# [[0, 2, 9], [1, 3, 6], [2, 5, 1], [3, 7, 3], [4, 8, 7]]
Note:
You may want to change the part
random.randint(0, 10)
to get the "N neighbour".
Let me know whether you like this code:
import random
array = [[0, 1, 2, 3, 4], [2, 3, 5, 7, 8], [9, 6, 1]]
max_len = max([len(l) for l in array])
dictionary = {}
for l in array:
for i in range(0,len(l)):
if dictionary.has_key(i):
dictionary[i].append(l[i])
else:
dictionary[i] = [l[i]]
for i in range(len(l),max_len):
if dictionary.has_key(i):
dictionary[i].append(random.choice(l))
else:
dictionary[i] = [random.choice(l)]
print dictionary.values()