Rearrange a python list into n lists, by column - python

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)

Related

python how to generate combinations from a list of lists

I hope you can help me, I want to generate combinations from the following list of lists (to work as a nxn matrix):
A = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
But I need that if e.g I take the first number of the first list, then as a matrix operation, remove the other elements of the column and the row of the selected element and then generate the possible combinations
For example, I choose the 1 on the first list, then the only possible combinations to generate are: (1,5,9) and (1,8,6) because the elimination the row and column.
I'm trying to build a recursive function to achieve that by removing column and row the problem is that I'm not sure about how to build the list with the combinations.
This is that I have so far:
list = []
def combinations(matrix):
matrix_rows = len(matrix)
if matrix_rows == 0:
# Base case
return matrix
else:
# Recursive case
# Always select first row
seq = []
for index, a in enumerate(matrix[0]):
E = a
seq.append(E)
# Remove i from row of index element a
new_matrix = remove_row(matrix, 0)
# Remove j from column index of element a
new_matrix = remove_column(new_matrix, index)
# Call again with new matrix
combinations(new_matrix)
list.append(seq)
return list
def remove_row(original_matrix, element_row_index):
new_matrix = []
if (len(original_matrix)) >= element_row_index:
new_matrix = original_matrix[:]
new_matrix.remove(original_matrix[element_row_index])
return new_matrix
def remove_column(matrix, index):
return [(x[0:index] + x[index + 1:]) for x in matrix]
With A matrix from above I'll expect to have:
A = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
print("Result: ", combinations(A))
Result: [[1,5,9], [1,6,8], [2,4,9], [2,6,7], [3,4,8], [3,5,7]]
Anyone can help me? Or give me a suggestion for a better approach
Added: An 4x4 example:
A = [[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]]
Results: [1,6,11,16], [1,6,12,15],[1,7,10,16], [1,7,12,14], [1,8,10, 15], [1,8,11, 14], ....
I think this can be done simply and with no recursion at all.
Basically, you want to choose all the possible permutations of range(n) on the rows (or columns) while going through the columns (or rows respectively) in order.
Here's one easy solution:
from itertools import permutations
import numpy as np
n = 3
x = np.arange(n ** 2).reshape((n, n)) + 1 # so as to fit in with your example
perms = permutations(range(n))
combinations = [list(x[range(n), p]) for p in perms]
print(combinations)
>> [[1, 5, 9], [1, 6, 8], [2, 4, 9], [2, 6, 7], [3, 4, 8], [3, 5, 7]]
If, however, you're not using numpy-compatible stuff, but rather a list-of-lists, here's a small tweak on the above that works just as well:
x = [[1, 'A'], [2, 'B']] # a "small" case so it's easy to follow
n = len(x)
index_list = range(n)
perms = permutations(index_list)
combinations = [[x[i][p[i]] for i in index_list] for p in perms]
print(combinations)
>> [[1, 'B'], ['A', 2]]
The above assumes you're still using "square" data. Meaning that the length of each inner list is the same length as the outer list containing them.
Hope that helps and that it does what you meant. If not please comment and I'll correct whatever's needed. I'll leave turning this into a function to the reader ;-)
Good luck!

Loop from a specific point in a list of lists Python

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! :)

Summing elements at the beginning with the elements at the end of a list

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.

Convert list of lists to list of integers

I need to convert a list of lists to a list of integers.
from:
L1 = [[1, 2, 3, 4], [3, 7, 1, 7], [0, 5, 6, 7], [9, 4, 5, 6]]
to:
L2 = [1234, 3717, 0567, 9456]
How can I make python recognize an integer starting with 0? Like the case L2[2]
The other question is, how can I check if items in a list are ordered?
A = [1, 2, 6, 9] ---->True
Other than this:
A == sorted(A)
You guys are FAST. Thanks!
The first question can be done by
L = [int("".join([str(y) for y in x])) for x in L]
Unfortunately, integers do not start with a 0. There is no way to do this.
Checking if A == sorted(A) is a perfectly fine way to do this.
L2 = [reduce(lambda x,y : 10 * x + y, l) for l in L1]
If you want a solution that doesn't go through strings.
For question 1, maybe Python 3 converts, but the plain .join give me a TypeError in Python 2. Try:
["".join(str(d) for d in x) for x in L]
...for the string representation, or
[int("".join(str(d) for d in x)) for x in L]
(The string representation is the only way to preserve leading zeros, except with formatted output...and then that's just string conversion on the way to the output file/string.)
For question 2: all(A[i-1] < A[i] for i in range(1, len(A)))
>>> A = [1, 2, 6, 9]
>>> all(A[i-1] < A[i] for i in range(1, len(A)))
True
You can do:
L2 = [ int("1" + "".join(str(l) for l in ll1)) for ll1 in L1 ]
to keep the zeros and get:
[11234, 13717, 10567, 19456]
but then you need to get rid of the leftmost 1s.

Modifying nested lists

How to handle nested lists in Python? I am having problem figuring out the syntax. Like example:
>>> l = [[1, 2, 3], [5, 6, 7]]
I want to square all the elements in this list. I tried:
[m*m for m in l]
But that doesn't work and throws up:
TypeError: can't multiply sequence by
non-int of type 'list'
because of the nested lists I guess?
How do I fix this?
>>> l = [[1, 2, 3], [5, 6, 7]]
>>> [[e*e for e in m] for m in l]
|-nested list-|
|---- complete list ---|
[[1, 4, 9], [25, 36, 49]]
Assuming you wanted the answer to look like this:
[[1, 4, 9], [25, 36, 49]]
You could do something like this:
l = [[1, 2, 3], [5, 6, 7]]
for x in range(len(l)):
for y in range(len(l[x])):
l[x][y] = l[x][y] * l[x][y]
print l
Obviously, the list comprehension answer is better.
[[1,2,3],[4,5,6]] != [1,2,3,4,5,6]
[map(lambda x: x *x,sl) for sl in l] #List comprhension
What you need is a recursive function, something like this:
def square(el):
if type(el) == list:
return [square(x) for x in el]
else:
return el**2;
I'd rather not get into the correctness of type(el) == list here, but you get the gist.
Of course, this is also doable with a list-comprehension, as many people have pointer out, provided that the structure is always the same. This recursive function can handle any level of recursion, and lists containing both lists and numbers.

Categories