How to properly use lists here? - python

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]]

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]

Nested list in list comprehension to for loop

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).

Move from an array of 'labels' to array of equations corresponding to those labels in Python 2.7

How can I efficiently move from an array of essentially labels to equations corresponding to those labels in python 2.7?
This image illustrates what I mean:
The equations pull values from array x, so "xn" in the image in python terms would be x[n]. As an example, the 0th entry in the label array is "a" which corresponds to the equation 1+xn which would be 1+x[0]. The next is "b" which is x[1]*2.
There are a plenty of ways to accomplish this, but I want to focus on efficiency. The actual arrays have thousands of elements, and this operation is performed thousands of times (each timestep in my model). The x array will be different at each timestep. What I am actually doing is building the diagonals for a tridiagonal matrix based on various boundary conditions.
Can anyone offer some insight better than iterating through the whole array each timestep with a switch case?
Here is an example of me doing it a brute way:
'''
Equations corresponding to various labels
a -> 2+x[n]
b -> 3*x[n-1]+2x[n]
c -> 4*x[n]
These are just dummy equations I am making up for the example
'''
x = [4,7,6,6,9,12,4,9,1,11]
labelArray = ['a','b','b','b','c','c','a','b','b','c']
outputArray = []
n = 0
for label in labelArray:
if label == 'a':
output = 2+x[n]
elif label == 'b':
output = 3*x[n-1]+2*x[n]
elif label == 'c':
output = 4*x[n]
outputArray.append(output)
n += 1
print outputArray
# outputArray = [6, 26, 33, 30, 36, 48, 6, 30, 29, 44]
Here's a solution I came up with. It should be faster and more concise, though it may not be the optimal solution.
from itertools import imap
# List of values
values = [4, 7, 6, 6, 9, 12, 4, 9, 1, 11]
# A list of corresponding methods for each value, must be same length as values.
# Optionally, you could create the data with the value and method in a tuple
# e.g. [(4, 'a'), (7, 'b') ... (x, 'y')]
# Though if you ensure both lists are of the same length, you can use the zip()
# method, which does the same thing.
methods = ['a', 'b', 'b', 'b', 'c', 'c', 'a', 'b', 'b', 'c']
# A dictionary with all your equations. You can also define them in a function
# elsewhere and include them like
# >{ 'a': external_function }
equations = {
# Lambda is just an anonymous function.
'a': lambda index: 2 + values[index],
'b': lambda index: 3 * values[index-1] + 2 * values[index],
'c': lambda index: 4 * values[index],
}
# Returns an iterator to prevent eating up your memory with one big array.
new_values = imap(lambda x,y: equations[x](y), methods, xrange(len(values)))
print [value for value in new_values]
Check out https://docs.python.org/2/library/functions.html for an explanation of the built in methods I'm using here.
Here's some info on iterators: http://anandology.com/python-practice-book/iterators.html
Here you have a version of your code that uses a dictionary and a map function. I hope it helps you.
functs = { 'a': '2+x[n]',
'b': '3*x[n-1] + 2*x[n]',
'c': '4*x[n]'}
x = [4, 7, 6, 6, 9, 12, 4, 9, 1, 11]
larray = ['a','b', 'b', 'b', 'c', 'c', 'a', 'b', 'b', 'c']
result = list(map(lambda n: eval(functs[larray[n]]), xrange(len(larray))))
print result
# result = [6, 26, 33, 30, 36, 48, 6, 30, 29, 44]

Python: all index of list greater than x [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
data = [10, 90, 20, 80, 30, 40, 70, 60]
A_list=[A,B,C,D,E,F,G,H]
How do I find all the values in data that are above 50.
Next how do I print so that it displays
B:90
D:80
H:60
G:70
Also I haven't used enumerate yet.
If you just want to print all the values higher then 50 a simple loop will do.
data = [10, 90, 20, 80, 30, 40, 70, 60]
for value in data:
if value > 50:
print(value)
If you need the indexes use this code. enumerate will give you an automatic counter.
data = [10, 90, 20, 80, 30, 40, 70, 60]
for index, value in enumerate(data):
if value > 50:
print(index)
If you need a list of indexes to print the values (your question is unclear at that point) then construct this list and loop over it.
data = [10, 90, 20, 80, 30, 40, 70, 60]
indexes = [index for index, value in enumerate(data) if value > 50]
for index in indexes:
print(data[index])
According to the question in your comment you could do the following (based on the last solution).
data = [10, 90, 20, 80, 30, 40, 70, 60]
characters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
indexes = [index for index, value in enumerate(data) if value > 50]
for index in indexes:
print('{}: {}'.format(characters[index], data[index]))
This code uses the index for both lists.
If this is homework and you can't use enumerate you have to construct the indexes list with a standard for loop.
indexes = []
for index in range(len(data)):
if data[index] > 50:
indexes.append(index)
A pythonic solution would be something like this.
data = [10, 90, 20, 80, 30, 40, 70, 60]
characters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
for char, value in zip(characters, data):
if value > 50:
print('{}: {}'.format(char, value))
In case you want the elements of the list which are greater than 50, you can simply use a list comprehension:
[el for el in lst if el>50]
where lst is your input list.
If you also wanted the index of those elements, you could:
[(i,el) for (i,el) in enumerate(lst) if el>50]
which would give you a list of tuples (index, element)
You want an if loop; if x is greater than one of the numbers, print it?
example:
myList = list(range(0,100))
for numb in myList:
if numb > 50:
print numb
Honestly, I'm not sure what OP wants to do. But this is just an example.
If you would like to use enumerate(), and you would like to store both the indexes of the numbers above 50 and the values themselves, one way would be to do it like so:
>>> a = [1,2,3,4,5,50,51,3,53,57]
>>> b, c = zip(*[(d, x) for d, x in enumerate(a) if x > 50])
>>> print b
(6, 8, 9)
>>> print c
(51, 53, 57)
Enumerate takes any object that supports iteration, and returns a tuple, (count, value), when the next() method of the iterator is called. Since enumerate() defaults to start its count at 0, and increments the count by one each iteration, we can use it to count the index of the array that the iteration is currently on.
Now, our list comprehension is returning a list of tuples, if we were to print the comprehension we would get:
>>> print [(d, x) for d, x in enumerate(a) if x > 50]
[(6, 51),(8, 53),(9, 57)]
Zip creates a list of tuples when given two arrays, for example:
>>> f = [1, 2, 3]
>>> g = [4, 5, 6]
>>> zipped = zip(f, g)
>>> zipped
[(1, 4), (2, 5), (3, 6)]
When used with the * operator, zip() will "unzip" a list.
So, when we "unzip" the list comprehension, two tuples are returned.
Hope this helps!

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

Categories

Resources