The answers by @SonderingNarcissit and @MadPhysicist are already quite nice.
Here is a quick way of adding a number to each element in your list and keeping the structure. You can replace the function return_number by anything you like, if you want to not only add a number but do something else with it:
def return_number(my_number):
return my_number + 4
def add_number(my_list):
if isinstance(my_list, (int, float)):
return return_number(my_list)
else:
return [add_number(xi) for xi in my_list]
A = [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0], [0], [0]]]
Then
print(add_number(A))
gives you the desired output:
[[[4, 4, 4], [4, 4, 4], [4, 4, 4]], [[4], [4], [4]]]
So what it does is that it look recursively through your list of lists and everytime it finds a number it adds the value 4; this should work for arbitrarily deep nested lists. That currently only works for numbers and lists; if you also have e.g. also dictionaries in your lists then you would have to add another if-clause.
Answer from Cleb on Stack OverflowThe answers by @SonderingNarcissit and @MadPhysicist are already quite nice.
Here is a quick way of adding a number to each element in your list and keeping the structure. You can replace the function return_number by anything you like, if you want to not only add a number but do something else with it:
def return_number(my_number):
return my_number + 4
def add_number(my_list):
if isinstance(my_list, (int, float)):
return return_number(my_list)
else:
return [add_number(xi) for xi in my_list]
A = [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0], [0], [0]]]
Then
print(add_number(A))
gives you the desired output:
[[[4, 4, 4], [4, 4, 4], [4, 4, 4]], [[4], [4], [4]]]
So what it does is that it look recursively through your list of lists and everytime it finds a number it adds the value 4; this should work for arbitrarily deep nested lists. That currently only works for numbers and lists; if you also have e.g. also dictionaries in your lists then you would have to add another if-clause.
Since numpy can only work with regular-shaped arrays, it checks that all the elements of a nested iterable are the same length for a given dimension. If they are not, it still creates an array, but of type np.object instead of np.int as you would expect:
>>> B = np.array(A)
>>> B
array([[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0], [0], [0]]], dtype=object)
In this case, the "objects" are lists. Addition is defined for lists, but only in terms of other lists that extend the original, hence your error. [0, 0] + 4 is an error, while [0, 0] + [4] is [0, 0, 4]. Neither is what you want.
It may be interesting that numpy will make the object portion of your array nest as low as possible. Array you created is actually a 2D numpy array containing lists, not a 1D array containing nested lists:
>>> B[0, 0]
[0, 0, 0]
>>> B[0, 0, 0]
Traceback (most recent call last):
File "<ipython-input-438-464a9bfa40bf>", line 1, in <module>
B[0, 0, 0]
IndexError: too many indices for array
As you pointed out, you have two options when it comes to ragged arrays. The first is to pad the array so it is non-ragged, convert it to numpy, and only use the elements you care about. This does not seem very convenient in your case.
The other method is to apply functions to your nested array directly. Luckily for you, I wrote a snippet/recipe in response to this question, which does exactly what you need, down to being able to support arbitrary levels of nesting and your choice of operators. I have upgraded it here to accept non-iterable nested elements anywhere along the list, including the original input and do a primitive form of broadcasting:
from itertools import repeat
def elementwiseApply(op, *iters):
def isIterable(x):
"""
This function is also defined in numpy as `numpy.iterable`.
"""
try:
iter(x)
except TypeError:
return False
return True
def apply(op, *items):
"""
Applies the operator to the given arguments. If any of the
arguments are iterable, the non-iterables are broadcast by
`itertools.repeat` and the function is applied recursively
on each element of the zipped result.
"""
elements = []
count = 0
for iter in items:
if isIterable(iter):
elements.append(iter)
count += 1
else:
elements.append(itertools.repeat(iter))
if count == 0:
return op(*items)
return [apply(op, *items) for items in zip(*elements)]
return apply(op, *iters)
This is a pretty general solution that will work with just about any kind of input. Here are a couple of sample runs showing how it is relevant to your question:
>>> from operator import add
>>> elementwiseApply(add, 4, 4)
8
>>> elementwiseApply(add, [4, 0], 4)
[8, 4]
>>> elementwiseApply(add, [(4,), [0, (1, 3, [1, 1, 1])]], 4)
[[8], [4, [5, 7, [5, 5, 5]]]]
>>> elementwiseApply(add, [[0, 0, 0], [0, 0], 0], [[4, 4, 4], [4, 4], 4])
[[4, 4, 4], [4, 4], 4]
>>> elementwiseApply(add, [(4,), [0, (1, 3, [1, 1, 1])]], [1, 1, 1])
[[5], [1, [2, 4, [2, 2, 2]]]]
The result is always a new list or scalar, depending on the types of the inputs. The number of inputs must be the number accepted by the operator. operator.add always takes two inputs, for example.
python - Convert a list of 2D numpy arrays to one 3D numpy array? - Stack Overflow
How to create n dimensional array in Numpy from a List?
What is 3D array in python?
Ho do do list comprehension on a numpy array?
If you build a 2D list and convert it to numpy with np.array() it will return a numpy array with 2 dimensions.
If you build a 3D list and convert it to numpy with np.array() it will return a numpy array with 3 dimensions.
Minimal working example:
my_list = [[[0,1,2],[0,1,2]],[[0,1,2],[0,1,2]]]
my_list
[[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]]
my_np_array = np.array(my_list)
my_np_array.shape
(2, 2, 3)
That's because this is not a 3D list. List has format [item,item]; 2D list would be [[],[]]. There are no inner level separators(',') in the file above. Load it into python and you get a 6,10 tuple back, the first valid entry after which no commas, so error out.
So this is my code:
import numpy as np
input="""2199943210
3987894921
9856789892
8767896789
9899965678"""
input = input.split("\n")
x = np.array([["2199943210"], ["3987894921"], ["9856789892"],
["8767896789"], ["9899965678"]])
I want to convert the input string to an ndarray like x. x i made manually by typing all that in. Can someone please tell me how to automate this? Like using a for loop & make the ndarray?
EDIT - AnSwEr FoUnD:
import numpy as np
input="""2199943210
3987894921
9856789892
8767896789
9899965678"""
input = input.split("\n")
X = np.empty(shape=[0, 1])
for i in input:
X = np.append(X, [[i]], axis=0)
print(X)