Related
I would like to append to a new list all elements of an existing list of lists after a specific point
m = [[1,2,3],[4,5,10],[6,2,1]]
specific point = m[0][2]
newlist = [3,4,5,10,6,2,1]
You can directly slice off the remainder of the first target list and then add on all subsequent elements, eg:
m = [[1,2,3],[4,5,10],[6,2,1]]
y, x = 0, 2
new_list = m[y][x:] + [v for el in m[y+1:] for v in el]
# [3, 4, 5, 10, 6, 2, 1]
Here's a couple of functional approaches for efficiently iterating over your data.
If sublists are evenly sized, and you know the index from where to begin extracting elements, use chain + islice:
from itertools import chain, islice
n = 3 # Sublist size.
i,j = 0,2
newlist = list(islice(chain.from_iterable(m), i*n + j, None))
If you don't know the size of your sublists in advance, you can use next to discard the first portion of your data.
V = chain.from_iterable(m)
next(v for v in V if v == m[i][j])
newlist = list(V)
newlist.insert(m[i][j], 0)
This assumes there is no identical value earlier in the sequence.
You can put a conditional in your iteration and only add based on that condition. Once you hit that specific index, make your condition true. Something like this:
m = [[1,2,3],[4,5,10],[6,2,1]]
specific_point = (0,2)
newlist = [3,4,5,10,6,2,1]
output = []
for i in range(len(m)):
for j in range(len(m[i])):
if (i,j) < specific_point:
continue
output.append(m[i][j])
output:
[3, 4, 5, 10, 6, 2, 1]
why not flatten the initial list and go from there
flat_list = [item for sublist in m for item in sublist]
would return [1,2,3,4,5,10,6,2,1] so now you're really on flat_list[2:]
Most of the answers only work for this specific shape of nested list, but it's also possible to create a solution that works with any shape of nested list.
def flatten_from(sequence, path=[]):
start = path.pop(0) if path else 0
for item in sequence[start:]:
if isinstance(item, (list, tuple)):
yield from flatten_from(item, path)
else:
yield item
With the example from the question
>>> list(flatten_from([[1, 2, 3], [4, 5, 10], [6, 2, 1]], [0, 2]))
[3, 4, 5, 10, 6, 2, 1]
It also works with any shape and level of nesting of the input data
m = [[1], [[2], [3, 4, 5, 6, 7]], 8, [9, [10, 11]]]
flatten_from(m, [])) # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
flatten_from(m, [2]) # 8, 9, 10, 11
flatten_from(m, [1, 1, 3]) # 6, 7, 8, 9, 10, 11
This is a bit of a bastard algorithm, though. On one hand, it uses nice functional programming concepts: recursion and yield.
On the other hand it relies on the side effect of mutating the path argument with list.pop, so it's not a pure function.
Below solution will work for your case where your array is restricted to list of list and the size of 'sublist' is consistent throughout i.e "3" in your case
m = [[1,2,3],[4,5,10],[6,2,1]] #input 2D array
a, b = 0, 2 #user input --> specific point a and b
flat_list_m = [item for firstlist in m for item in firstlist] #flat the 2D list
print (flat_list_m[len(m[0])*a+b:]) #print from specific position a and b, considering your sublist length is consistent throughout.
I hope this helps! :)
Given a list of numbers, create a new list of numbers such that the first and last numbers are added and stored as the first number, the second and second-to-last numbers are stored as the second number, and so on
num_list = [1,2,3,4,5,6]
num_list2 = [num_list[-1] + num_list[0], num_list[-2] + num_list[1],
num_list[-3] + num_list[2]]
print(num_list2)
output is [7,7,7]
I got the correct output this way but I am sure this is not an efficient way to do it. Is there a better way? I also am supposed to check for even and odd length of the list and if its an odd number of integers, add the central integer in the original list to the end of the new list but don't know how I would go about doing this
I think this is more efficient, i just simply did a for loop:
num_list2 = []
num_list = [1,2,3,4,5,6]
for i in range(round(len(num_list)/2)):
num_list2.append(num_list[i]+num_list[-(i+1)])
print(num_list2)
Output:
[7, 7, 7]
Let us using reversed
[x + y for x, y in zip(num_list, list(reversed(num_list)))][:len(num_list)//2]
Out[406]: [7, 7, 7]
Here's an inefficient[1], but clear way of doing this:
from itertools import zip_longest # or izip_longest in Python2
lst = [1,2,3,4,5,6]
chop_index = len(lst) // 2 # (or +1, depending on how you want to handle odd sized lists)
lh, rh = lst[:chop_index], lst[:chop_index-1:-1]
print(lh, rh) # To see what's going on in the "chopping"
sums = [x + y for (x,y) in zip_longest(lh, rh, fillvalue=0)]
print(sums)
You could improve it by using islice and reversed iterators, or use index math exclusively.
Output:
lst = [1,2,3,4,5,6] => [7, 7, 7]
lst = [1,2,3,4,5,6,7] => [8, 8, 8, 4]
[1] This makes two copies of the list parts. For long lists this is silly, and you shouldn't use this method. It was mostly written to highlight zip_longest's fillvalue optional argument.
Using itertools.islice on a generator:
from itertools import islice
num_list = [1,2,3,4,5,6]
generator = (x + y for x, y in zip(num_list, num_list[::-1]))
print(list(islice(generator, len(num_list)//2)))
# [7, 7, 7]
You can use the following method, which is compatible with asymmetrical list.
def sum_start_end(list_):
result = [x + y for x, y in zip(list_, list_[::-1])][:len(list_) // 2]
if len(list_) % 2 != 0:
result.append(list_[len(list_) // 2])
return result
so for a symmetric list
>>> num_list = [1, 2, 3, 4, 5, 6]
>>> sum_start_end(num_list)
[7, 7, 7]
and for asymmetric list
>>> num_list = [1, 2, 3, 4, 5, 6, 7]
>>> sum_start_end(num_list)
[8, 8, 8, 4]
It's simpler than you imagine.
Just observe your manual attempt and try to infer from it. We can simply do
x = len(num_list)//2 + len(num_list)%2
for i in range(x):
sumBoth = num_list[i] + num_list[-i-1]
num_list2.append(sumBoth)
or with a simpler one-liner
num_list2 = [ num_list[i] + num_list[-i-1] for i in range(len(num_list)//2+len(num_list)%2)]
This works for even as well as odd lengths because of the len(num_list)%2 at the end in the range.
I've been trying to make a function that can take two lists of any size (say, list A and list B) and sees if list B occurs in list A, but consecutively and in the same order. If the above is true, it returns True, else it'll return False
e.g.
A:[9,0,**1,2,3,4,5,6,**7,8] and B:[1,2,3,4,5,6] is successful
A:[1,2,0,3,4,0,5,6,0] and B:[1,2,3,4,5,6] is unsuccessful.
A:[1,2,3,4,5,6] and B [6,5,3,2,1,4] fails because despite having the same
numbers, they aren't in the same order
I've tried doing this using nested loops so far and am a bit confused as to where to go
Just try this:
L1 = [9,0,1,2,3,4,5,6,7,8]
L2 = [1,2,3,4,5,6]
c = 0
w = 0
for a in range(len(L2)):
for b in range(w+1, len(L1)):
if L2[a] == L1[b]:
c = c+1
w = b
break
else:
c = 0
if c == len(L2):
print('yes')
break
Here you check if the element of l2 is in l1 and if so breaks the first loops remember where you left and of the next element of l2 is the same as the next element of l1 and so on.
And the last part is to check if this happened as much times as the length of l2. if so then you know that the statement is correct!
if your arrays are not huge and if you can find a way to map each element in your array to a string you can use:
list1 = [9,0,1,2,3,4,5,6,7,8]
list2 = [1,2,3,4,5,6]
if ''.join(str(e) for e in list2) in ''.join(str(e) for e in list1):
print 'true'
it just make two string from the lists and than use 'in' to find any accorence
Use any function
any(A[i:i+len(B)] == B for i in range(len(A) - len(B) + 1))
demo
i converted the entire list into a string and then found a substring of that string
the list when converted to a string it becomes
str(a)='[9,0,1,2,3,4,5,6,7,8]'
which when when we strip the string becomes
str(a).strip('[]')='9,0,1,2,3,4,5,6,7,8'
Now the problem just converted to
checking if there is a substring in the the string
so we can us the in operator to check the substring
The solution
a=[9,0,1,2,3,4,5,6,7,8]
b=[1,2,3,4,5,6]
print(str(b).strip('[]') in str(a).strip(']['))
testcase1
testcase2
Try this:
L1 = [9,2,1,2,0,4,5,6,7,8]
L2 = [1,2,3,4,5,6]
def sameorder(L1,L2):
for i in range(len(L1)-len(L2)+1):
if L1[i:len(L2)+i]==L2:
return True
return False
You can create sublists of a that can be analyzed:
def is_consecutive(a, b):
return any(all(c == d for c, d in zip(b, i)) for i in [a[e:e+len(b)] for e in range(len(a)-len(b))])
cases = [[[9, 0, 1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6]], [[1, 2, 0, 3, 4, 0, 5, 6, 0], [1, 2, 3, 4, 5, 6]], [[1, 2, 3, 4, 5, 6], [6, 5, 3, 2, 1, 4]]]
final_cases = {"case_{}".format(i):is_consecutive(*a) for i, a in enumerate(cases, start=1)}
Output:
{'case_3': False, 'case_2': False, 'case_1': True}
I have four arrays, say, A, B, C and D, of the same size NumElements, and I want to remove all the 0s in them. If A has a zero, B, C and D have one too, in the same position. So I was thinking to loop over the elements of A:
for n in range(NumElements):
if A[n]==0:
A.pop(n)
B.pop(n)
C.pop(n)
D.pop(n)
Of course, this doesn't work, because popping 0s from the arrays reduces their sizes, so I end up trying to access A[NumElements-1], when now A is only NumElements-m long. I know I should work with array copies, but the arrays are quite long and I'd like to keep memory consumption low, since I'm working in a Java virtual machine (don't ask :(((( ). Also, I'd like an approach which is efficient, but most of all readable (this code must be maintained by Python illiterates like me, so I need to KISS).
a,b,c,d = [filter(lambda i: i != 0, l) for l in [a,b,c,d]]
Filter each list removing elements that are not 0.
Edit,
Just to explain whats happening
Filter takes an expression and "filters" the list, by applying the function to everything in the list, everything that does not return True.
Lambda is a short hand for a function
So
a = [1,2,3,4,5,6,7,8]
def is_even(x):
return x % 2 == 0
filter(is_even, a)
If they all have zeros in the same place, then loop over the index in reverse and remove that index from each list:
for i in reversed(range(NumElements)):
if not A[i]:
del A[i], B[i], C[i], D[i]
By looping over the list in reverse, you keep the indices stable (only elements past the current index have been removed, shrinking only the tail of the lists). Since you are not using the return value of list.pop() (all you get is 0s anyway, right?), you may as well just use del on the list index instead.
I used reversed(range(NumElements)) here instead of calculating the more strenuous range(NumElements - 1, -1, -1); it is just as efficient but a lot more readable. The reversed() function returns an iterator, handling the reversed number sequence very efficiently. On Python 2, you can do the same with xrange():
for i in reversed(xrange(NumElements)):
Demo:
>>> A = [1, 2, 0, 4, 5, 0]
>>> B = [2, 4, 0, 10, 9, 0]
>>> C = [5, 3, 0, 10, 8, 0]
>>> D = [10, 3, 0, 1, 34, 0]
>>> for i in reversed(range(NumElements)):
... if not A[i]:
... del A[i], B[i], C[i], D[i]
...
>>> A, B, C, D
([1, 2, 4, 5], [2, 4, 10, 9], [5, 3, 10, 8], [10, 3, 1, 34])
Just work from the other end!
for n in range(NumElements-1,-1,-1):
if A[n]==0:
A.pop(n)
B.pop(n)
C.pop(n)
D.pop(n)
I think you could do smth like this. I don't know if it's pythonic enough.
A = [1, 2, 4, 0]
B = [6, 0, 4, 3, 9]
C = [12, 5, 32, 0, 90]
for row in [A, B, C]:
for i, v in enumerate(row):
if v == 0: del row[i]
or, if you sure that indexes of zero are equal in all lists:
for i in range(len(A) - 1, -1, -1):
if A[i] == 0:
for row in [A, B, C]:
del row[i]
Look at my other answer List accessing in Python. You can walk through list A and store indexes of 0s in temporary list and then pop them.
This is probably a hack but it's simple and it works
>>> a = [1,2,3]
>>> b = [1,10,99]
>>> c = [1,87,22]
>>> d = []
>>> d.extend([a,b,c])
>>> to_remove = 1
>>> [i.remove(to_remove) for i in d]
>>> d
[[2, 3], [10, 99], [87, 22]]
Note that this will remove all elements marked as to_remove not just zeros at the beginning, I'm assuming this is ok for you because you say that you want to remove all the zeros.
I want to rearrange a list l into a list of n lists, where n is the number of columns.
e.g.,
l = [1,2,3,4,5,6,7,8,9,10]
n = 4
==> [[1,5,9],[2,6,10],[3,7][4,8]]
Can someone please help me out with an algorithm? Feel free to use any python awesomeness that's available; I'm sure theres some cool mechanism that's a good fit for this, i just can't think of it.
PS The example list just happened to be ordered numbers starting at 1. That's not my actual scenario.
There is indeed a cool mechanism for this in Python: the three-argument form of slicing, where the last argument is step size.
>>> l = [1,2,3,4,5,6,7,8,9,10]
>>> n = 4
>>> [l[i::n] for i in range(n)]
[[1, 5, 9], [2, 6, 10], [3, 7], [4, 8]]
l = [1,2,3,4,5,6,7,8,9,10]
n = 4
def f(l,n):
A = []
[A.append([]) for i in xrange(n)]
[ A [(i - 1) % n].append(i) for i in l]
return A
print f(l,n)
[[1, 5, 9], [2, 6, 10], [3, 7], [4, 8]]
The following function does what you want to achieve:
def rearrange(seq,n):
return [[v for i,v in enumerate(seq[x:]) if i%n==0] for x in xrange(len(seq))][:n]
Writing Python isn't a game of code golf, don't be afraid to use more than one line for the sake of readability.
l = [1,2,3,4,5,6,7,8]
def split_into_columns(input_list, num_of_cols=3):
retval = [ [] for _ in xrange(num_of_cols)] # build 3 columns
for i in xrange(len(input_list)): # iterate through original list
retval[i%num_of_cols].append(input_list[i]) # place in the "modulo 3" column
return retval
# here's a compressed, less readable version of that for-loop
#[retval[i%3].append(input_list[i]) for i in xrange(len(input_list))]
#return retval
print split_into_columns(l, 3)