Nested list in list comprehension to for loop - python

I am taking a class to learn python. We are in the section covering list comprehension and I am having a hard time understanding what is happening in one of the examples. I am trying to convert it back to a for loop to understand what is happening but and I am running into an issue.
Example: 1 This I am able to convert into a FOR loop just fine. The output is the same
my_list1 = [ x * y for x in [20, 40, 60] for y in [2, 4, 6]]
print('My list 1', my_list1)
my_list2 = []
for x in [20, 40, 60]:
for y in [2, 4, 6]:
my_list2.append(x*y)
print(my_list2)
OUTPUT
My list 1 [40, 80, 120, 80, 160, 240, 120, 240, 360]
My list 2 [40, 80, 120, 80, 160, 240, 120, 240, 360]
Example 2: I am having a problem with converting into a FOR loop. My output is different. I don't know how to get a list to output within a list. The second set of [] is what is throwing me off. I don't know where they need to go when converting into to a FOR loop to get a list within as list as a result.
Can you someone explain what I am doing wrong?
my_list3 = [[x * y for x in [20, 40, 60]] for y in [2, 4, 6]]
print('My list 3', my_list3)
my_list4 = []
for x in [20, 40, 60]:
for y in [2, 4, 6]:
my_list4.append([x*y])
print('My list4', my_list4)
OUTPUT
My list 3 [[40, 80, 120], [80, 160, 240], [120, 240, 360]]
My list4 [[40], [80], [120], [80], [160], [240], [120], [240], [360]]

I see that it's more complicated because they want you to have a list of lists in your output. Each element you add to my_list4 must be a list itself.
If the assignment is to remove all list comprehensions, you will have to build up a sublist one item at a time, and then add the sublist to the parent list. Like this:
for x in [20, 40, 60]:
sublist = [] # make an empty sublist
for y in [2, 4, 6]:
sublist.append(x*y) # put a single value into the sublist
my_list4.append(sublist) # add the completed sublist onto the parent list
While I prefer the above approach for clarity, you can also avoid making the temporary list by adding the empty sublist to the parent list in advance, and constantly referring to it while you add values:
for x in [20, 40, 60]:
my_list4.append([]) # append the empty sublist to the parent list
for y in [2, 4, 6]:
my_list4[-1].append(x*y) # use [-1] to reference the last item
# in my_list4, which is the current sublist.
Your attempt was making a one-element list for each combination of x and y (the square brackets around each individual value show you this).

Related

Removing elements from a list using indexs from another

I have written a function that collects all index positions of 'NULL' and 'NaN' strings that appear in a list and append them to another list called num. I am now trying to write a function that goes through the list that holds the strings 'NULL' and 'NaN' and uses the index positions from the num list to remove them.
I have coded these so far without success.
l = ['NULL', 32, 43, 'NaN', 45, 89, 11, 'NULL']
num = [0, 3, 7]
def rowRemover():
for i in num:
l.pop(num[i])
rowRemover()
print(l)
def rowRemover():
i = 0
while i < len(num):
l.pop(num[i])
i += 1
rowRemover()
print(l)
I would appreciate your help. Thanks
Instead of popping elements from a list, consider a list comprehension. Since we'll be checking if indices match and checking if an item exists in a set is cheaper than doing the same with a list, convert num to num_set. Then enumerate function will help you identify which elements to exclude:
l = ['NULL', 32, 43, 'NaN', 45, 89, 11, 'NULL']
num_set = set([0, 3, 7])
new_l = [x for i, x in enumerate(l) if i not in num_set]
Output:
[32, 43, 45, 89, 11]

How to properly use lists here?

My issue is as follows: I want to create a program that accepts a random list (l) from the list. This randomly chosen list, in its turn, contains other lists. Then it should find the shortest list inside l and cut all other lists inside l by the length of the shortest one. These lists should be appended to a new list (l_exit) as follows: [l[1][1], l[2][1], ... , l[i][1], l[1][2], ... , l[i][k]]. Then all elements, which have been cut, should be added to the end of l_exit.
Input: [[1,2,3],['a', 'b'], [30, 40, 50, 60]]
Output: [1, 'a', 30, 2, 'b', 40], [3, 50, 60]
(shortest length is 2 (['a','b']). we cut every list by 2 and
therefore have new following lists [1,2],['a','b'],[30,40]. They are
added accordingly to l_exit[0] (firstly go first elements of each
list, secondly - second and so on). In the end we add a new list of
items that have been left, that have been cut from pre-existing lists: 3,50,60)
When I try running the program with above-mentioned input, I have the following output:
changed l: [[1, 2, 3], ['a', 'b'], [30, 40, 50, 60]]
l_exit: [[40, 'b', 2, 30, 'a', 1, 1],[]]
What can be the source of the problem? I will appreciate any help! Thanks in advance!
The program:
import random
l_1 = [[1,2,3],['a', 'b'], [30, 40, 50, 60]]
l_2 = [[1,2,3,4,5],['a', 'b','c'], [30, 40, 50, 120]]
l_3 = [[1],['a', 'b'], [30, 40, 50, 60, 101, 120]]
l_rand = [l_1,l_2,l_3]
l = random.choice(l_rand)
l_exit = [[],[]]
if (len(l[1]) < len(l[2])):
index = len(l[1])
else:
index = len(l[2])
for i in range (len(l)):
if (len(l[i]) < index):
l_exit[1] = l[i][index:]
l[i] = l[i][:index]
for i in range (index):
for k in range(len(l)):
l_exit.insert(0,(l[k][i]))
print('changed l:', l)
print('l_exit: ', l_exit)
You can use the zip function to get your first part. First we 'unpack' using the *, then we loop over the lists:
x = [[1,2,3],['a', 'b'], [30, 40, 50, 60]]
out = []
for i in zip(*x):
out.extend([*i])
out
#[1, 'a', 30, 2, 'b', 40]
zip finishes at the shortest element, so we are done.
To get the remainder list, we can do a little extra work to figure out where we finished, using a counter, and then subset the original lists:
out = []
left = []
count = 0
for i in zip(*x):
out.extend([*i])
count += 1
for i in x:
left.extend(i[count:])
out, left
#([1, 'a', 30, 2, 'b', 40], [3, 50, 60])
Defining index
Firstly, there is an issue in the following if/else tree:
if (len(l[1]) < len(l[2])):
index = len(l[1])
else:
index = len(l[2])
What happens in the case that l[0] is the shortest list within l? Or cases in which the longest list within l has an index >2?
If index is to be defined as "An integer representing the len of the shortest list stored within l" then I would suggest the following:
index = len(sorted(l, key=len)[0])
The code is quite concise and basically runs as "The value of index is the len of the first list stored in a copy of l that has been sorted by len". This will stop unexpected/undesirable behaviour that may be generated by your original index definition as discussed above.
Populating l_exit
As far as I understand, l_exit should be a list containing:
A list containing all values up to (but not including as to account for index from 0) the index of index from each list within l - stored in l_exit[0]
A list containing all values from the index of index from each list within l - stored in l_exit[1]
First you try to populate l_exit[1] using the following loop:
for i in range (len(l)):
if (len(l[i]) < index):
l_exit[1] = l[i][index:]
l[i] = l[i][:index]
The problem here is that given index refers to a value that is the shortest len of an element in the top-level of the list l (as discussed previously this may not be reliable in the current implementation but would be in the example output you provided), the code held in the if len(l[i]) < index): block will never execute - since by definition no len(l[i]) for i in l could be < index.
Conclusion
I won't go into further detail on issues within your code here as I feel it is obvious that you should spend some time reviewing each statement/structure, debugging with a debugger or console printouts as best fits your attitude - could you state what each line of your code is doing if asked?
I would however recommend looking into the built-in enumerate() method - enumerate docs - as I feel that you might be able to use this to good effect as to improve the readability/maintainability of your code.
Solution
I think it would be time well spent to review your existing code yourself, but for what it's worth here's my full solution to the problem posed.
import random
l_1 = [[1,2,3],['a', 'b'], [30, 40, 50, 60]]
l_2 = [[1,2,3,4,5],['a', 'b','c'], [30, 40, 50, 120]]
l_3 = [[1],['a', 'b'], [30, 40, 50, 60, 101, 120]]
l_rand = [l_1,l_2,l_3]
l = random.choice(l_rand)
index = len(sorted(l, key=len)[0])
l_exit = [[j for i in l for j in i[:index]], [y for x in l for y in x[index:]]]
print(f'l: {l}')
print(f'l_exit: {l_exit}')
Test Output
l: [[1, 2, 3], ['a', 'b'], [30, 40, 50, 60]]
l_exit: [[1, 2, 'a', 'b', 30, 40], [3, 50, 60]]

Check if double of element in first list is present in second list and print the output

Suppose
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 14, 68, 56]
Compare List1 and List2 and print the element of List1 which have a double value in List2
Output = [23,7,34]
Try this:
Output = [i for i in List1 if i*2 in List2]
You can convert list2 to a set for efficient lookups, and use a list comprehension with the said condition for the desired output:
set2 = set(List2)
[i for i in List1 if i * 2 in set2]
You already have the answer but just of the sake of simplicity. Basically you want to iterate through List1 and check if double value is in List2. If so add element to the output array.
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 7, 14, 68, 56]
output = []
for i in List1:
if i*2 in List2:
output.append(i)
print output
You already got the answers. However, just for fun, I came up with the following method. I did not benchmark all the approaches listed here. It can be fun to do that. This is an interesting question and can be investigated more. However, just for the sake of it I present the solution I did.
import numpy as np
l = np.array(List1) * 2
print(l)
## array([46, 90, 12, 14, 68])
print(set(l) & set(List2))
## {68, 46, 14}
l2 = set(l) & set(List2)
print([List1[list(np.nonzero(l == i))[0][0]] for i in l if i in l2])
## [23, 7, 34]
It uses the broadcasting of numpy along with the fast intersection operation of Python set. This maybe useful if the two lists are very big.

Finding the difference between consecutive numbers in a list (Python)

Given a list of numbers, I am trying to write a code that finds the difference between consecutive elements. For instance, A = [1, 10, 100, 50, 40] so the output of the function should be [0, 9, 90, 50, 10]. Here is what I have so far trying to use recursion:
def deviation(A):
if len(A) < 2:
return
else:
return [abs(A[0]-A[1])] + [deviation(A[1: ])]
The output I get, however, (using the above example of A as the input) is [9, [90, [50, [10, None]]]]. How do I properly format my brackets? (I've tried guessing and checking but I this is the closest I have gotten) And how do I write this where it subtracts the current element from the previous element without getting an index error for the first element? I still want the first element of the output list to be zero but I do not know how to go about this using recursion and for some reason that seems the best route to me.
You can do:
[y-x for x, y in zip(A[:-1], A[1:])]
>>> A = [1, 10, 100, 50, 40]
>>> [y-x for x, y in zip(A[:-1], A[1:])]
[9, 90, -50, -10]
Note that the difference will be negative if the right side is smaller, you can easily fix this (If you consider this wrong), I'll leave the solution for you.
Explanation:
The best explanation you can get is simply printing each part of the list comprehension.
A[:-1] returns the list without the last element: [1, 10, 100, 50]
A[1:] returns the list without the first element: [10, 100, 50, 40]
zip(A[:-1], A[1:]) returns [(1, 10), (10, 100), (100, 50), (50, 40)]
The last step is simply returning the difference in each tuple.
The simplest (laziest) solution is to use the numpy function diff:
>>> A = [1, 10, 100, 50, 40]
>>> np.diff(A)
array([ 9, 90, -50, -10])
If you want the absolute value of the differences (as you've implied by your question), then take the absolute value of the array.
[abs(j-A[i+1]) for i,j in enumerate(A[:-1])]
You can do a list comprehension:
>>> A = [1, 10, 100, 50, 40]
>>> l=[A[0]]+A
>>> [abs(l[i-1]-l[i]) for i in range(1,len(l))]
[0, 9, 90, 50, 10]
For a longer recursive solution more in line with your original approach:
def deviation(A) :
if len(A) < 2 :
return []
else :
return [abs(A[0]-A[1])] + deviation(A[1:])
Your bracket issue is with your recursive call. Since you have your [deviation(a[1: ])] in its own [] brackets, with every recursive call you're going to be creating a new list, resulting in your many lists within lists.
In order to fix the None issue, just change your base case to an empty list []. Now your function will add 'nothing' to the end of your recursively made list, as opposed to the inherent None that comes with a blank return'
Actually recursion is an overkill:
def deviation(A):
yield 0
for i in range(len(A) - 1):
yield abs(A[i+1] - A[i])
Example:
>>> A = [3, 5, 2]
>>> list(deviation(A))
[0, 2, 3]
EDIT: Yet, another, even simplier and more efficient solution would be this:
def deviation(A):
prev = A[0]
for el in A:
yield abs(el - prev)
prev = el

Removing all duplicates from the list - keeping no instance of a duplicate item

I've got a list:
myList = [-3, -3, 6, 10, 10, 16, 16, 40, 40, 60, 60, 100, 100, 140, 140, 211, -8]
how can I efficiently remove all the duplicated items from the, i.e. to have a new list like this:
[6,211,-8]
I know a way to do it, by keeping a track of duplicated items, and then removing them using python set(), i.e.
listOfDuplicates = [x for x, y in collections.Counter(myList).items() if y > 1]
newList = list(set(myList) - set(listOfDuplicates))
Is there any better way of doing this (preserving the order) in python?
The best way is to invert the condition, as suggested by Jonathon Reinhart
import collections
print [x for x, y in collections.Counter(myList).iteritems() if y == 1]
# [6, 211, -8]
Note: This method will not be able to maintain the order of elements. For example, when
myList = [1, 1000, 10]
the result is
[1000, 1, 10]
Because collections.Counter is internally a dictionary only. As dictionaries use hashing, the order cannot be guaranteed.
To preserver Order, you can do like this, as suggested by DSM
c = Counter(myList)
print [x for x in myList if c[x] == 1]
myList = [-3, -3, 6, 10, 10, 16, 16, 40, 40, 60, 60, 100, 100, 140, 140, 211, -8]
b=[]
d=[]
for x in myList:
try:
w=b.index(x)
if w!=None:
d.append(x)
del b[w]
except:
b.append(x)
b=set(b)-set(d)
print list(b)
this will not preserve order too

Categories

Resources