Concatenate arrays by column in python - python

I have a list of arrays, where each array is a list of lists. I want to turn this into a single array with all the columns. I've tried using for loops to get this done, but it feels like it should be doable in list comprehension. Is there a nice one-liner that will do this?
Example Input: [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
Desired Output: [[1,2,7,8],[3,4,9,10],[5,6,11,12]]
Note: Example only has two arrays in the main list, but my actual data has much more, so I'm looking for something that works for N subarrays.
Edit:
Example trying to solve this
Works for two but doesn't generalize:
[input[0][i]+input[1][i] for i in range(len(input[0]))]
These don't work, but show the idea:
[[element for table in input for element in row] for row in table]
[[*imput[j][i] for j in range(len(input))] for i in range(len(input[0]))]
Edit: Selected answer that uses only list comprehension and zip, but all answers (as of now) work, so use whichever fits your style/use case best.

You can generalize this from the standard list flattening pattern and zip:
>>> L = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
>>> list([y for z in x for y in z] for x in zip(*L))
[[1, 2, 7, 8], [3, 4, 9, 10], [5, 6, 11, 12]]
>>> L = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]],[[13,14],[15,16],[17,18]]]
>>> list([y for z in x for y in z] for x in zip(*L))
[[1, 2, 7, 8, 13, 14], [3, 4, 9, 10, 15, 16], [5, 6, 11, 12, 17, 18]]

Here is one way of doing it:
initial = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
output = [a+b for a, b in zip(*initial)]
print(output)
If you have more lists, this also works:
import itertools
initial = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]],[[13,14],[15,16],[17,18]]]
output = [list(itertools.chain.from_iterable(values)) for values in zip(*initial)]
print(output)

If you don't mind it is a tuple in the list.You could also try:
from itertools import chain
a = [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]], [[13, 14], [15, 16], [17, 18]]]
output = list(map(list, map(chain.from_iterable, zip(*a))))
# [[1, 2, 7, 8, 13, 14], [3, 4, 9, 10, 15, 16], [5, 6, 11, 12, 17, 18]]

This would do it, I named your input first:
[*map(lambda x: list(i for s in x for i in s), zip(*first))]
[[1, 2, 7, 8], [3, 4, 9, 10], [5, 6, 11, 12]]

Related

How to delete multiple columns from a list of lists

test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
If I want to remove column 2, that is [5,7,16] from the list, I know I can use:
[j.pop(1) for j in test_list]
however, if I want to move 2 columns at the same time, that is [5,7,16] and [8,9,20], how can I change the code, so the result is:
The modified mesh after column deletion : [[4, 6], [2, 10], [12, 18]]
Here's one other way:
columns_to_remove = (1,3)
new_object = [[x for i,x in enumerate(l) if i not in columns_to_remove] for l in test_list]
Note that this creates a new object without modifying the original test_list.
test_list = [[4, 5, 6, 8], [2, 7, 10, 9],[12, 16, 18, 20]]
removeIndex = [1,3] # The indices you want to remove
for l in test_list:
for i,v in enumerate(removeIndex):
l.pop(v-i)
print(test_list)
You can try list comprehension with required indices
NOTE: I am not altering the original list, it is creating brand new list
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
[[i[0], i[2]] for i in test_list]
[[4, 6], [2, 10], [12, 18]]
You can delete multiple columns using a numpy array. Please look at numpy.delete() for documentation.
import numpy as np
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
a = np.array(test_list)
a = np.delete(a, [1, 3], axis=1)
print (a)
The output will be:
[[ 4 6]
[ 2 10]
[12 18]]
You can also use numpy.delete with slice() if you want to remove a column or a set of columns.
If you want to remove 2nd and 3rd column, you can give:
np.delete(a, slice(1, 3), axis=1)
array([[ 4, 8],
[ 2, 9],
[12, 20]])
If you want to delete 2 and 4th column, you can use slice(start, stop, skip) option as follows:
np.delete(a, slice(1, None,2), 1)
Output of this will be:
array([[ 4, 6],
[ 2, 10],
[12, 18]])
If you want the numpy array to be stored back as a regular list of list, you can always do a.tolist()
You can do it easily with numpy:
import numpy as np
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
a = np.array(test_list)
a = np.delete(a, [1,3], axis=1)
print(a)
#output:
[[ 4 6]
[ 2 10]
[12 18]]

How to slice tensorflow tensor differently for each row at once?

I have simple tensor
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
and want to slice it, but I need to do it differently for each of the rows. This slice operation is described by another tensor
b = tf.constant([[0, 1], [2, 4], [2, 5]])
It means that from the first row of tensor a I need elements from 0 to 1, from the second row from 2 to 4 and so on. So the final final result will be
[
[1],
[8, 9],
[13, 14, 15]
]
My first idea was to fill ranges between begin and end of a slice, but unfortunately, doing it with map_fn is not possible because result's rows have different lengths.
Does anyone know how to do such operation?
Basically we have two arrays to iterate. One with actual data, other with range to return.
Therefore, zip function can help iterate over elements from multiple arrays one by one.
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
b = tf.constant([[0, 1], [2, 4], [2, 5]])
# As you iterate, provided a and b have same length
# [1, 2, 3, 4, 5] sliced as [0:1]
# [6, 7, 8, 9, 10] sliced as [2:4]
# [11, 12, 13, 14, 15] sliced as [2:5]
[data.numpy().tolist()[start:end] for data, (start, end) in zip(a,b)]
Output:
[[1], [8, 9], [13, 14, 15]]
If the size of b is known at graph compile time, then you can slice each row separately.
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
b = tf.constant([[0, 1], [2, 4], [2, 5]])
r = []
for i in range(3):
bi = b[i]
r.append(a[i][bi[0]: bi[1]])
print(r)

Writing a diagonal of a matrix (2D list) function

I want to write a function that accepts one argument, a square 2D matrix, and returns the diagonal of the entered matrix from the interactive window of IDLE.
I have tried several ways but whenever I input a matrix (1 to 16 in a 4 × 4) I get a TypeError saying 4 positional arguments but 5 were given.
I have messed around with it trying to use input() to be able to enter the matrix I want but I still get the same error.
This is what I want to be able to do:
>>> m1 = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> diagonal(m1)
[1, 6, 11, 16]
How would I go about this? I have also seen a lot of posts using Numpy but I am not entirely sure if it is allowed to use on this assignment.
enumerate() is very convenient here with a square matrix because it will give you the proper indexes as you loop through your arrays. You can use it in a comprehension to get both the correct index and the correct matrix.
def diagonal(mat):
return [el[i] for i, el in enumerate(mat)]
m1 = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
diagonal(m1)
>> [1, 6, 11, 16]
Try this:
def diagonal(m1):
n = len(m1)
l = []
for i in range(n):
l.append(m1[i][i])
return l
m1 = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
print(diagonal(m1))

How to multiply each element of two nested lists?

There are 2 nested lists, I want to multiply items at corresponding positions, so that the output is [[9, 16, 21], [24, 25, 24], [21, 16, 9]].
I use the program below. It works, but it seems too complex. Is that any quick way to do it? Is there any library to quickly perform such a task?
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = [[9, 8, 7], [6, 5, 4], [3, 2, 1]]
n = []
for i in range(3):
m = []
for j in range(3):
m.append(a[i][j] * b[i][j])
n.append(m)
print(n)
You can apply zip twice:
a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b=[[9, 8, 7], [6, 5, 4], [3, 2, 1]]
result = [[j*k for j, k in zip(c, d)] for c, d in zip(a, b)]
Output:
[[9, 16, 21], [24, 25, 24], [21, 16, 9]]
You can map the lists to the multiplication operator:
from functools import partial
from operator import mul
print(list(map(list, map(partial(map, mul), a, b))))
Output:
[[9, 16, 21], [24, 25, 24], [21, 16, 9]]
If you're using Python 2.x you can skip the conversion to lists as well:
print map(partial(map, mul), a, b)

How to generate a 2D list which will contain numbers from 1..n without using numpy?

The 2D list should be like this:
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
I am unable to find the logic for this. I have done this using numpy's reshape function. But unable to do without numpy.
Here is one simple way:
res = [list(range(i, i+4)) for i in range(1, 14, 4)]
print(res)
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
You can also wrap in a generic function:
def square(n):
return [list(range(i, i+n)) for i in range(1, n**2, n)]
res = square(4)
Explanation
The syntax for range construction is range(start, end, [step]). step is optional; if it is not specified, it is assumed to be 1.
The first part range(i, i+n) creates a range object from i to i+n-1, inclusive.
The second part range(1, n**2, n) iterates in steps of n to n*n, not including the final term. Since end is non-inclusive, squaring n provides the desired cap.
This is one approach
l = range(1, 17) #Create a list using range
print([l[i:i+4] for i in range(0, len(l), 4)]) #Divide the list into 4 equal chunks
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
I like this one too:
>> [[i+4*j for i in range(1,5)] for j in range(4)]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
Use a list-comprehension like this with tuple unpacking:
>>> [[*range(i, i+4)] for i in range(1, 14, 4)]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
or you could use the grouper from the itertools recipes to split a given list (or iterable) into an 2d matrix. this is something along those lines:
def to2d(items, width):
return list(list(i) for i in zip(*(iter(items_1d),) * width))
items_1d = list(range(1, 17)) # or just items_1d = range(1, 17)
print(to2d(items=items_1d, width=4))

Categories

Resources