If else logic in python nested list comprehension - python

I have a list which could consist of either lists or integers or None. I want to flatten the iterable elements (assuming only lists for now) inside this list to individual elements.
for eg:
[[0, 1], [2, 3], 1, 3, 4, 0, None] into [0,1,2,3,1,3,4,0,None]
using list comprehension. I found another similar question but all those elements were iterable in that list, since mine has integers too how do I use if else logic in the list comprehension for the first "for loop". I am trying something like this, but not sure what the exact syntax is to flatten out.
[ item sublist if isinstance(sublist,list) else [sublist] for
sublist in A for item in sublist ]
Based on other questions, if-else should occur prior to for loops and for loops have to occur in order. I am unable to insert if else after the first for loop, syntax allows only if and not else.
Could someone help with syntax of this please, for doing if-else on the first for loop or any intermediate for loop in nested for loops in comprehension?

You can use a generator to convert your mixed list into an iterable that only has lists:
gen = (x if isinstance(x, collections.Iterable) else [x] for x in A)
Then you can use the standard flattening idiom to flatten out the generator:
flattened = [y for x in gen for y in x]

#mgilson gave an elegant solution using a comprehension. It is also possible to do so in a natural loop using error-trapping:
items = [[0, 1], [2, 3], 1, 3, 4, 0, None]
flattened = []
for item in items:
try:
flattened.extend(item)
except TypeError:
flattened.append(item)
print(flattened) #prints [0, 1, 2, 3, 1, 3, 4, 0, None]

Related

Python - ValueError: Too many values to unpack

I have a very simple code where I want to loop through two lists at the same time. However, this gives me a ValueError: too many values to unpack.
def testing_something():
list1 = [1,2,3,4,45]
list2 = [1,4,4]
return list1, list2
for q,z in testing_something():
print (q,z)
The output of testing_something() is ([1, 2, 3, 4, 45], [1, 4, 4]), so I can imagine to be able to loop simultaneously through this output, with q in my case being [1, 2, 3, 4, 45] and z being [1,4,4]. Why does this raise a ValueError?
you can't use a single for to iterate over two lists at the same time. You should use zip function
def testing_something():
list1 = [1,2,3,4,45]
list2 = [1,4,4]
return list1, list2
for q,z in zip(testing_something()):
print(q)
print(z)
Note that zip will iterate until the lists have elements: if it finishes iterating over one, it will stop iterating. This is solved with itertools.zip_longest, which would output None in correspondence of the out-of-bound index: should you want to use it, you have to import the itertools module
If you want q=[1, 2, 3, 4, 45] and z=[1,4,4] in the first (and only) iteration of the for loop, you should return [[list1, list2]].
However, if you plan to only have one pair of lists returned, you can skip the for loop altogether (and keep the code you posted in the question):
q, z = testing_something()
print(q, z)
you can't iterate over single variable as your doing in your for loop,this is the easy way to q,z as your lists.
def testing_something():
list1 = [1,2,3,4,45]
list2 = [1,4,4]
return list1, list2
q,z=testing_something()
print q
print z

List of strings to array of integers

From a list of strings, like this one:
example_list = ['010','101']
I need to get an array of integers, where each row is each one of the strings, being each character in one column, like this one:
example_array = np.array([[0,1,0],[1,0,1]])
I have tried with this code, but it isn't working:
example_array = np.empty([2,3],dtype=int)
i = 0 ; j = 0
for string in example_list:
for bit in string:
example_array[i,j] = int(bit)
j+=1
i+=1
Can anyone help me? I am using Python 3.6.
Thank you in advance for your help!
If all strings are the same length (this is crucial to building a contiguous array), then use view to efficiently separate the characters.
r = np.array(example_list)
r = r.view('<U1').reshape(*r.shape, -1).astype(int)
print(r)
array([[0, 1, 0],
[1, 0, 1]])
You could also go the list comprehension route.
r = np.array([[*map(int, list(l))] for l in example_list])
print(r)
array([[0, 1, 0],
[1, 0, 1]])
The simplest way is to use a list comprehension because it automatically generates the output list for you, which can be easily converted to a numpy array. You could do this using multiple for loops, but then you are stuck creating your list, sub lists, and appending to them. While not difficult, the code looks more elegant with list comprehensions.
Try this:
newList = np.array([[int(b) for b in a] for a in example_list])
newList now looks like this:
>>> newList
... [[0, 1, 0], [1, 0, 1]]
Note: there is not need to invoke map at this point, though that certainly works.
So what is going on here? We are iterating through your original list of strings (example_list) item-by-item, then iterating through each character within the current item. Functionally, this is equivalent to...
newList = []
for a in example_list:
tmpList = []
for b in a:
tmpList.append(int(b))
newList.append(tmpList)
newList = np.array(newList)
Personally, I find the multiple for loops to be easier to understand for beginners. However, once you grasp the list comprehensions you probably won't want to go back.
You could do this with map:
example_array = map(lambda x: map(lambda y: int(y), list(x)), example_list)
The outer lambda performs a list(x) operation on each item in example_list. For example, '010' => ['0','1','0']. The inner lambda converts the individual characters (resultants from list(x)) to integers. For example, ['0','1','0'] => [0,1,0].

Remove a list inside a list

I want to remove the list [1,2,3] inside the outer list.
I tried or isinstance(item, list) but that didn't work, the nested list was still there.
messy_list = ["a", 2, 3, 1, False, [1, 2, 3]]
# Your code goes below here
messy_list.pop(3)
messy_list.insert(0,1)
for item in messy_list:
if isinstance(item, str) or isinstance(item, bool):
messy_list.remove(item)
messy_list.pop(-1)
print(messy_list)
I would like to know if there wasn't a better way to check if there's a list inside the list, and then remove from the outer list, instead of having to hardcode it with .pop(-1)
Will remove ALL inner lists:
messy_list = ["a", 2, 3, 1, False, [1, 2, 3]]
cleaned = [item for item in messy_list if not isinstance(item,list)]
print(cleaned)
I am using a list comprehension that inspects all items of your messy_list and only adds it to the resulting new list if it is not a list itself.
We can remove a list inside a list same way like we remove the single list, just provide the reference of the list object to the del function.
del(list_object).
for example :-
a = [1,2,3,[4,5,6]]
del(a[3])
after this a will look like.
[1, 2, 3]

Is it safe practice to edit a list while looping through it?

I was trying to execute a for loop like:
a = [1,2,3,4,5,6,7]
for i in range(0, len(a), 1):
if a[i] == 4:
a.remove(a[i])
I end up having an index error since the length of the list becomes shorter but the iterator i does not become aware.
So, my question is, how can something like that be coded? Can the range of i be updated in each iterations of the loop based on current array condition?
For the .pop() that you mention for example you can use a list comprehension to create a second list or even modify the original one in place. Like so:
alist = [1, 2, 3, 4, 1, 2, 3, 5, 5, 4, 2]
alist = [x for x in alist if x != 4]
print(alist)
#[1, 2, 3, 1, 2, 3, 5, 5, 2]
As user2393256 more generally puts it, you can generalize and define a function my_filter() which will return a boolean based on some check you implement in it. And then you can do:
def my_filter(a_value):
return True if a_value != 4 else False
alist = [x for x in alist if my_filter(x)]
I would go with the function solution if the check was too complicated to type in the list comprehension, so mainly for readability. The example above is therefore not the best since the check is very simple but i just wanted to show you how it would be done.
If you want to delete elements from your list while iterating over it you should use list comprehension.
a = [1,2,3,4,5,6,7]
a = [x for x in a if not check(x)]
You would need to write a "check" function that returns wether or not you want to keep the element in the list.
I don't know where you are going with that but this would do what I beleive you want :
i=0
a = [1,2,3,4,5,6,7]
while boolean_should_i_stop_the_loop :
if i>=len(a) :
boolean_should_i_stop_the_loop = False
#here goes what you want to do in the for loop
print i;
a.append(4)
i += 1

Using for loop in Python 3.4 to remove particular element from array

As I am new to programming in Python. I am trying to remove particular elements from array using for loop which looks like
a=[2,3,1,4,1,1,1,5]
n=a.count(1)
for i in range (len(a)-n):
if (a[i]==1):
del a[i]
else:
a[i]=a[i]
print (a)
I want to remove 1 from array a. But, I am getting result as:
[2, 3, 4, 1, 1, 5].
That is 1 still exists in my new array. Can somebody please answer my problem?
try like this:
a = [2,3,1,4,1,1,1,5]
a = [x for x in a if x!=1] # this is called list comprehension
note Never modify list while iterating
Use a while loop and the remove method:
a = [2, 3, 1, 4, 1, 1, 1, 5]
while 1 in a:
a.remove(1)
print a
The real answer to your question (which none of the other answers addresses) is that every time you remove an item, the index i moves past it.
in your case:
a = [2,3,1,4,1,1,1,5]
after deleting the 5th item in the original list, the pointer moves to the 6th item, and the new 5th item (the second 1 in the sequence of three 1s) is skipped.
Regarding the comment never modify a list in a loop, try to implement an in-place algorithm like Fisher-Yates without modifying the list. Never say never. Know what you're doing.
The OP changes the list in-place, not creating a new list.
There are two methods, the second is safe, the first might be faster.
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(len(a)-1, -1, -1):
if a[i] == toremove:
del a[i]
and
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(a.count(toremove)):
a.remove(toremove)
The second removes the element however many times it exists (before the loop). Since we are not iterating on the list, it is safe to use the remove method.
Both fragments should be O(n) (but haven't done the calculations).
You can copy a and then remove but you cannot iterate over and delete elements from the same list, if your list starts with n elements python will have n pointers to each element so removing elements from the list as your are iterating over it will cause elements to be missed.python has no way of knowing you have removed elements from the list:
a = [2,3,1,4,1,1,1,5]
for ele in a[:]:
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
You can also use reversed which returns and iterator avoiding creating a whole copy of the list at once:
a = [2,3,1,4,1,1,1,5]
for ele in reversed(a):
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
Or using a list comprehension with the [:] syntax so we actually update the original object:
a[:] = (ele for ele in a if ele != 1)
All the above are linear operations using a single pass over a.
Actually as the del statement will remove elements from your list , and as the list that you bound in your loop doesn't been update after the first deleting you remove incorrect elements from your list , so if you want to use del you need to make the list name in your loop to reference to new list , that you can use a function for this aim , but as a more python way you can just use a list comprehension:
>>> a=[2,3,1,4,1,1,1,5]
>>> a=[i for i in a if i !=1]
>>> a
[2, 3, 4, 5]
Or you can use filter :
>>> a=[2,3,1,4,1,1,1,5]
>>> a=filter(lambda x: x !=1,a)
>>> a
[2, 3, 4, 5]

Categories