How to generate new list from variable in a loop? - python

My actual example is more involved so I boiled the concept down to a simple example:
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
print calc
For each iteration of my loop, I end up with a variable (calc) I'd like to use to populate a new list. My actual process involves much more than multiplying the value by 10, so I'd like to be able to set each value in the new list by this method. The new code might look like this:
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
# set calc as x'th entry in a new list called l2 (x = iteration cycle)
print l2
Then it would print the new list: [10,20,30,40,...]

There are several options...
List comprehensions
Use list comprehension, if short enough:
new_list = [number * 10 for number in old_list]
map()
You could also use map(), if the function exists before (or you will eg. use lambda):
def my_func(value):
return value * 10
new_list = map(my_func, old_list)
Be aware, that in Python 3.x map() does not return a list (so you would need to do something like this: new_list = list(map(my_func, old_list))).
Filling other list using simple for ... in loop
Alternatively you could use simple loop - it is still valid and Pythonic:
new_list = []
for item in old_list:
new_list.append(item * 10)
Generators
Sometimes, if you have a lot of processing (as you said you have), you want to perform it lazily, when requested, or just the result may be too big, you may wish to use generators. Generators remember the way to generate next element and forget whatever happened before (I am simplifying), so you can iterate through them once (but you can also explicitly create eg. list that stores all the results).
In your case, if this is only for printing, you could use this:
def process_list(old_list):
for item in old_list:
new_item = ... # lots of processing - item into new_item
yield new_item
And then print it:
for new_item in process_list(old_list):
print(new_item)
More on generators you can find in Python's wiki: http://wiki.python.org/moin/Generators
Accessing "iteration number"
But if your question is more about how to retrieve the number of iteration, take a look at enumerate():
for index, item in enumerate(old_list):
print('Item at index %r is %r' % (index, item))

Here's how to do it without jumping straight into list comprehensions. It's not a great idea to use l as a variable name because it is identical to 1 in some fonts, so I changed it (althought l1 isn't really much better :) )
l1 = [1,2,3,4,5,6,7,8]
l2 = []
for number in l1:
calc = number*10
print calc
l2.append(calc)
list comprehensions do provide a more compact way to write this pattern
l2 = [ number*10 for number in l1 ]

Use a list comprehension :
>>> l = [1,2,3,4,5,6,7,8]
>>> l2 = [ item*10 for item in l]
>>> l2
[10, 20, 30, 40, 50, 60, 70, 80]
Which is roughly equivalent to, but a list comprehension is faster than normal for-loop:
>>> l2 = []
>>> for number in l:
... calc = number * 10 #do some more calculations
... l2.append(calc) #appends the final calculated value at the end of l2
...
>>> l2
[10, 20, 30, 40, 50, 60, 70, 80]
You can also create a function for all the calculations you're doing, and then call the function inside the list comprehension :
def solve(x):
#do some calculations here
return calculated_value
l2 = [ solve(item) for item in l]

So I believe you would like to apply a function to every element of the list.
Have you tried a list comprehension?
[num*10 for num in l]
Should give you what you need for this simple example.
Naturally, if you have some more complex set of operations you can use a function you defined earlier, to wit:
def explode(n):
return (n + (n * n) - (3 * n))
[explode(num) for num in l]

A simple answer to your problem would be to append calc to a list as shown below:
l = [1,2,3,4,5,6,7,8]
your_list = []
for number in l:
calc = number*10
your_list.append(calc)
To access variables in the list, use slicing syntax.
ie, the 2nd element in a list would be your_list[1], the 5th your_list[4].
I suspect you'll need to empty the list at some point. To do so with slicing, use calc[:] = []

Everyone else has given you the right answer: use a list comprehension.
I will give you an alternate right answer: Use map with a lambda or a function.
You can use a lambda when the 'function' is very simple:
print map(lambda x: x*10,[1,2,3,4,5,6,7,8])
# [10, 20, 30, 40, 50, 60, 70, 80]
The function used by map can be of arbitrary complexity, and then it is easier use a function:
def more_complex(x):
# can be as complex as a function can be
# for now -- *10
return x*10
print map(more_complex,[1,2,3,4,5,6,7,8])
But that would work with a comprehension as well:
l2=[more_complex(x) for x in [1,2,3,4,5,6,7,8]]
Just so that you are familiar with the form of map vs list comprehension.

loop that generates the list
KOT = []
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
KOT.append(calc)
You get the KOT list
KOT = [10, 20, 30, 40, 50, 60, 70, 80]

Related

Declare long list in python

my_list = [20,21,22 ........ 60]
in python, how can I easily declare above list with 40 elements in it. Instead of typing all the 40 elements. i know for loop can be used to append to a different list. but is there any easiest way ?
If you want a list of this specific type, you can just use
my_list = list(range(20, 61))
or if the definition becomes more complex, you can use list comprehension, like
my_list = [i*i for i in range(10, 20)]
The solution is to define a range (default step size is 1 like in your example) and transform it to a list. Make sure that the last value in range() is the last value you want +1.
mylist = list(range(20,61))
You can apply for-loop combined with range()-function in your code in order to append elements to my_list.
my_list = [20] # Initial list
for i in range(21, 61):
my_list.append(i) # Append elements
Verify that there are 41 elements in your list (from 20 to 60)
if len(my_list) == 41:
print(True)
else:
print(False)

Pandas: create a list from the printed output of a for-loop [duplicate]

My actual example is more involved so I boiled the concept down to a simple example:
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
print calc
For each iteration of my loop, I end up with a variable (calc) I'd like to use to populate a new list. My actual process involves much more than multiplying the value by 10, so I'd like to be able to set each value in the new list by this method. The new code might look like this:
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
# set calc as x'th entry in a new list called l2 (x = iteration cycle)
print l2
Then it would print the new list: [10,20,30,40,...]
There are several options...
List comprehensions
Use list comprehension, if short enough:
new_list = [number * 10 for number in old_list]
map()
You could also use map(), if the function exists before (or you will eg. use lambda):
def my_func(value):
return value * 10
new_list = map(my_func, old_list)
Be aware, that in Python 3.x map() does not return a list (so you would need to do something like this: new_list = list(map(my_func, old_list))).
Filling other list using simple for ... in loop
Alternatively you could use simple loop - it is still valid and Pythonic:
new_list = []
for item in old_list:
new_list.append(item * 10)
Generators
Sometimes, if you have a lot of processing (as you said you have), you want to perform it lazily, when requested, or just the result may be too big, you may wish to use generators. Generators remember the way to generate next element and forget whatever happened before (I am simplifying), so you can iterate through them once (but you can also explicitly create eg. list that stores all the results).
In your case, if this is only for printing, you could use this:
def process_list(old_list):
for item in old_list:
new_item = ... # lots of processing - item into new_item
yield new_item
And then print it:
for new_item in process_list(old_list):
print(new_item)
More on generators you can find in Python's wiki: http://wiki.python.org/moin/Generators
Accessing "iteration number"
But if your question is more about how to retrieve the number of iteration, take a look at enumerate():
for index, item in enumerate(old_list):
print('Item at index %r is %r' % (index, item))
Here's how to do it without jumping straight into list comprehensions. It's not a great idea to use l as a variable name because it is identical to 1 in some fonts, so I changed it (althought l1 isn't really much better :) )
l1 = [1,2,3,4,5,6,7,8]
l2 = []
for number in l1:
calc = number*10
print calc
l2.append(calc)
list comprehensions do provide a more compact way to write this pattern
l2 = [ number*10 for number in l1 ]
Use a list comprehension :
>>> l = [1,2,3,4,5,6,7,8]
>>> l2 = [ item*10 for item in l]
>>> l2
[10, 20, 30, 40, 50, 60, 70, 80]
Which is roughly equivalent to, but a list comprehension is faster than normal for-loop:
>>> l2 = []
>>> for number in l:
... calc = number * 10 #do some more calculations
... l2.append(calc) #appends the final calculated value at the end of l2
...
>>> l2
[10, 20, 30, 40, 50, 60, 70, 80]
You can also create a function for all the calculations you're doing, and then call the function inside the list comprehension :
def solve(x):
#do some calculations here
return calculated_value
l2 = [ solve(item) for item in l]
So I believe you would like to apply a function to every element of the list.
Have you tried a list comprehension?
[num*10 for num in l]
Should give you what you need for this simple example.
Naturally, if you have some more complex set of operations you can use a function you defined earlier, to wit:
def explode(n):
return (n + (n * n) - (3 * n))
[explode(num) for num in l]
A simple answer to your problem would be to append calc to a list as shown below:
l = [1,2,3,4,5,6,7,8]
your_list = []
for number in l:
calc = number*10
your_list.append(calc)
To access variables in the list, use slicing syntax.
ie, the 2nd element in a list would be your_list[1], the 5th your_list[4].
I suspect you'll need to empty the list at some point. To do so with slicing, use calc[:] = []
Everyone else has given you the right answer: use a list comprehension.
I will give you an alternate right answer: Use map with a lambda or a function.
You can use a lambda when the 'function' is very simple:
print map(lambda x: x*10,[1,2,3,4,5,6,7,8])
# [10, 20, 30, 40, 50, 60, 70, 80]
The function used by map can be of arbitrary complexity, and then it is easier use a function:
def more_complex(x):
# can be as complex as a function can be
# for now -- *10
return x*10
print map(more_complex,[1,2,3,4,5,6,7,8])
But that would work with a comprehension as well:
l2=[more_complex(x) for x in [1,2,3,4,5,6,7,8]]
Just so that you are familiar with the form of map vs list comprehension.
loop that generates the list
KOT = []
l = [1,2,3,4,5,6,7,8]
for number in l:
calc = number*10
KOT.append(calc)
You get the KOT list
KOT = [10, 20, 30, 40, 50, 60, 70, 80]

Check number not a sum of 2 ints on a list

Given a list of integers, I want to check a second list and remove from the first only those which can not be made from the sum of two numbers from the second. So given a = [3,19,20] and b = [1,2,17], I'd want [3,19].
Seems like a a cinch with two nested loops - except that I've gotten stuck with break and continue commands.
Here's what I have:
def myFunction(list_a, list_b):
for i in list_a:
for a in list_b:
for b in list_b:
if a + b == i:
break
else:
continue
break
else:
continue
list_a.remove(i)
return list_a
I know what I need to do, just the syntax seems unnecessarily confusing. Can someone show me an easier way? TIA!
You can do like this,
In [13]: from itertools import combinations
In [15]: [item for item in a if item in [sum(i) for i in combinations(b,2)]]
Out[15]: [3, 19]
combinations will give all possible combinations in b and get the list of sum. And just check the value is present in a
Edit
If you don't want to use the itertools wrote a function for it. Like this,
def comb(s):
for i, v1 in enumerate(s):
for j in range(i+1, len(s)):
yield [v1, s[j]]
result = [item for item in a if item in [sum(i) for i in comb(b)]]
Comments on code:
It's very dangerous to delete elements from a list while iterating over it. Perhaps you could append items you want to keep to a new list, and return that.
Your current algorithm is O(nm^2), where n is the size of list_a, and m is the size of list_b. This is pretty inefficient, but a good start to the problem.
Thee's also a lot of unnecessary continue and break statements, which can lead to complicated code that is hard to debug.
You also put everything into one function. If you split up each task into different functions, such as dedicating one function to finding pairs, and one for checking each item in list_a against list_b. This is a way of splitting problems into smaller problems, and using them to solve the bigger problem.
Overall I think your function is doing too much, and the logic could be condensed into much simpler code by breaking down the problem.
Another approach:
Since I found this task interesting, I decided to try it myself. My outlined approach is illustrated below.
1. You can first check if a list has a pair of a given sum in O(n) time using hashing:
def check_pairs(lst, sums):
lookup = set()
for x in lst:
current = sums - x
if current in lookup:
return True
lookup.add(x)
return False
2. Then you could use this function to check if any any pair in list_b is equal to the sum of numbers iterated in list_a:
def remove_first_sum(list_a, list_b):
new_list_a = []
for x in list_a:
check = check_pairs(list_b, x)
if check:
new_list_a.append(x)
return new_list_a
Which keeps numbers in list_a that contribute to a sum of two numbers in list_b.
3. The above can also be written with a list comprehension:
def remove_first_sum(list_a, list_b):
return [x for x in list_a if check_pairs(list_b, x)]
Both of which works as follows:
>>> remove_first_sum([3,19,20], [1,2,17])
[3, 19]
>>> remove_first_sum([3,19,20,18], [1,2,17])
[3, 19, 18]
>>> remove_first_sum([1,2,5,6],[2,3,4])
[5, 6]
Note: Overall the algorithm above is O(n) time complexity, which doesn't require anything too complicated. However, this also leads to O(n) extra auxiliary space, because a set is kept to record what items have been seen.
You can do it by first creating all possible sum combinations, then filtering out elements which don't belong to that combination list
Define the input lists
>>> a = [3,19,20]
>>> b = [1,2,17]
Next we will define all possible combinations of sum of two elements
>>> y = [i+j for k,j in enumerate(b) for i in b[k+1:]]
Next we will apply a function to every element of list a and check if it is present in above calculated list. map function can be use with an if/else clause. map will yield None in case of else clause is successful. To cater for this we can filter the list to remove None values
>>> list(filter(None, map(lambda x: x if x in y else None,a)))
The above operation will output:
>>> [3,19]
You can also write a one-line by combining all these lines into one, but I don't recommend this.
you can try something like that:
a = [3,19,20]
b= [1,2,17,5]
n_m_s=[]
data=[n_m_s.append(i+j) for i in b for j in b if i+j in a]
print(set(n_m_s))
print("after remove")
final_data=[]
for j,i in enumerate(a):
if i not in n_m_s:
final_data.append(i)
print(final_data)
output:
{19, 3}
after remove
[20]

Find monotonic sequences in a list?

I'm new in Python but basically I want to create sub-groups of element from the list with a double loop, therefore I gonna compare the first element with the next to figure out if I can create these sublist, otherwise I will break the loop inside and I want continue with the last element but in the main loop:
Example: 5,7,8,4,11
Compare 5 with 7, is minor? yes so include in the newlist and with the inside for continue with the next 8, is minor than 5? yes, so include in newlist, but when compare with 4, I break the loop so I want continue in m with these 4 to start with the next, in this case with 11...
for m in xrange(len(path)):
for i in xrange(m+1,len(path)):
if (path[i] > path[m]):
newlist.append(path[i])
else:
break
m=m+i
Thanks for suggestions or other ideas to achieve it!
P.S.
Some input will be:
input: [45,78,120,47,58,50,32,34]
output: [45,78,120],[47,58],50,[32,34]
The idea why i want make a double loops due to to compare sub groups of the full list,in other way is while 45 is minor than the next one just add in the new list, if not take the next to compare in this case will be 47 and start to compare with 58.
No loop!
Well at least, no explicit looping...
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use a dictionary here to work around closure limitations
state = { 'prev': lst[0], 'n': 0 }
def grouper(x):
if x < state['prev']:
state['n'] += 1
state['prev'] = x
return state['n']
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
Usage (work both with Python 2 & Python 3):
>>> data = [45,78,120,47,58,50,32,34]
>>> print (list(process(data)))
[[45, 78, 120], [47, 58], [50], [32, 34]]
Joke apart, if you need to group items in a list itertools.groupby deserves a little bit of attention. Not always the easiest/best answer -- but worth to make a try...
EDIT: If you don't like closures -- and prefer using an object to hold the state, here is an alternative:
class process:
def __call__(self, lst):
if len(lst) < 1:
return lst
self.prev = lst[0]
self.n = 0
return [ list(g) for k, g in itertools.groupby(lst, self._grouper) ]
def _grouper(self, x):
if x < self.prev:
self.n += 1
self.prev = x
return self.n
data = [45,78,120,47,58,50,32,34]
print (list(process()(data)))
EDIT2: Since I prefer closures ... but #torek don't like the dictionary syntax, here a third variation around the same solution:
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use an object here to work around closure limitations
state = type('State', (object,), dict(prev=lst[0], n=0))
def grouper(x):
if x < state.prev:
state.n += 1
state.prev = x
return state.n
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
data = [45,78,120,47,58,50,32,34]
print (list(process(data)))
I used a double loop as well, but put the inner loop in a function:
#!/usr/bin/env python
def process(lst):
def prefix(lst):
pre = []
while lst and (not pre or pre[-1] <= lst[0]):
pre.append(lst[0])
lst = lst[1:]
return pre, lst
res=[]
while lst:
subres, lst = prefix(lst)
res.append(subres)
return res
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], [50], [32, 34]]
The prefix function basically splits a list into 2; the first part is composed of the first ascending numbers, the second is the rest that still needs to be processed (or the empty list, if we are done).
The main function then simply assembles the first parts in a result lists, and hands the rest back to the inner function.
I'm not sure about the single value 50; in your example it's not in a sublist, but in mine it is. If it is a requirement, then change
res.append(subres)
to
res.append(subres[0] if len(subres)==1 else subres)
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], 50, [32, 34]]
#uselpa's version is fine. Here's mine (same issue with [50] instead of just 50) that uses collections.deque to be a little more efficient, and also some long comments...
#! /usr/bin/env python
from collections import deque
def process(lst):
"""
Given a list of values that is not sorted (such that for some
valid indices i,j, i<j, sometimes lst[i] > lst[j]), produce a
new list-of-lists, such that in the new list, each sublist *is*
sorted:
for all sublist \elem returnval:
assert_is_sorted(sublist)
and furthermore this is the minimal set of sublists required
to achieve the condition.
Thus, if the input list lst is actually sorted, this returns
[list(lst)].
"""
def sublist(deq):
"""
Pop items off the front of deque deq until the next one
goes backwards. Return the constructed sub-list.
"""
sub = [deq.popleft()]
while deq and deq[0] >= sub[-1]:
sub.append(deq.popleft())
return sub
# Make a copy of lst before modifying it; use a deque so that
# we can pull entries off it cheaply.
deq = deque(lst)
output = []
ret = []
while deq:
ret.append(sublist(deq))
return ret
print process([45,78,120,47,58,50,32,34])
(Incidentally, in the days before collections.deque I'd probably just use a reversed copy of lst and use lst.pop() in sublist. That's not quite as obvious, though.)
why not simply use a single for loop instead of using itertool and all fancy stuff.
def list_test(inlist, outlist):
if not inlist:
return []
prev=inlist[0]
x=[]
for item in inlist:
if item >= prev:
x.append(item)
else:
outlist.append(x)
x=[]
x.append(item)
prev=item
if x:
outlist.append(x)
in_list=[1,0,1,2,3]
out_list = []
list_test(in_list, out_list)
print(out_list)
O/p:[[1], [0, 1, 2, 3]]

Linear merging for lists in Python

I'm working through Google's Python class exercises. One of the exercises is this:
Given two lists sorted in increasing order, create and return a merged list of all the elements in sorted order. You may modify the passed in lists. Ideally, the solution should work in "linear" time, making a single pass of both lists.
The solution I came up with was:
def linear_merge(list1, list2):
list1.extend(list2)
return sorted(list1)
It passed the the test function, but the solution given is this:
def linear_merge(list1, list2):
result = []
# Look at the two lists so long as both are non-empty.
# Take whichever element [0] is smaller.
while len(list1) and len(list2):
if list1[0] < list2[0]:
result.append(list1.pop(0))
else:
result.append(list2.pop(0))
# Now tack on what's left
result.extend(list1)
result.extend(list2)
return result
Included as part of the solution was this:
Note: the solution above is kind of cute, but unfortunately list.pop(0) is
not constant time with the standard python list implementation, so the
above is not strictly linear time. An alternate approach uses pop(-1) to
remove the endmost elements from each list, building a solution list which
is backwards. Then use reversed() to put the result back in the correct
order. That solution works in linear time, but is more ugly.
Why are these two solutions so different? Am I missing something, or are they being unnecessarily complicated?
They're encouraging you to think about the actual method (algorithm) of merging two sorted lists. Suppose you had two stacks of paper with names on them, each in alphabetical order, and you wanted to make one sorted stack from them. You wouldn't just lump them together and then sort that from scratch; that would be too much work. You'd make use of the fact that each pile is already sorted, so you can just take the one that comes first off of one pile or the other, and put them into a new stack.
As you noted, your solution works perfectly. So why the complexity? Well, for a start
Ideally, the solution should work in "linear" time, making a single
pass of both lists.
Well, you're not explicitly passing through any lists, but you are calling sorted(). So how many times will sorted() pass over the lists?
Well, I don't actually know. Normally, a sorting algorithm would operate in something like O(n*log(n)) time, though look at this quote from the Python docs:
The Timsort algorithm used in Python does multiple sorts efficiently
because it can take advantage of any ordering already present in a
dataset.
Maybe someone who knows timsort better can figure it out.
But what they're doing in the solution, is using the fact that they know they have 2 sorted lists. So rather than starting from "scratch" with sorted, they're picking off elements 1 by 1.
I like the #Abhijit approach the most. Here is a slightly more pythonic/readable version of his code snippet:
def linear_merge(list1, list2):
result = []
while list1 and list2:
result.append((list1 if list1[-1] > list2[-1] else list2).pop(-1))
return (result + list1 + list2)[-1::-1]
With the help of the built-in python features, we:
don't need to explicitly check if the lists are empty with the
len function.
can merge/append empty lists and the result will remain unchanged, so no need for explicit checking.
we can combine multiple statements (if the readability allows), which sometimes makes the code more compact.
result = []
while list1 and list2:
result.append((list1 if list1[-1] > list2[-1] else list2).pop(-1))
if len(list1):
result += list1[-1::-1]
if len(list2):
result += list2[-1::-1]
return result[-1::-1]
The solution by #Abhijit and #intel do not work in all cases because they have not reversed the leftover parts of the original lists. If we have list1 = [1, 2, 3, 5, 9, 11, 13, 17] and list2 = [6, 7, 12, 15] then their solution would give [5, 3, 2, 1, 6, 7, 9, 11, 12, 13, 15, 17] where we would want [1, 2, 3, 5, 6, 7, 9, 11, 12, 13, 15, 17].
Your solution is O(n log n), which means that if your lists were 10 times as long, the program would take (roughly) 30 times as much time. Their solution would only take 10 times as long.
Pop off the end of the lists until one is empty. I think this is linear, and also the reverses are linear too. Ugly, but a solution.
def linear_merge(list1, list2):
# NOT return sorted (list1 + list2), as this is not linear
list3 = []
rem = []
empty = False
while not empty:
# Get last items from each list, if they exist
if len (list1) > 0:
a = list1[-1]
else:
rem = list2[:]
empty = True
if len (list2) > 0:
b = list2[-1]
else:
rem = list1[:]
empty = True
# Pop the one that's largest onto the new list
if not empty:
if a > b:
list3.append (a)
list1.pop ()
else:
list3.append (b)
list2.pop ()
# add the (reversed) remainder to the list
rem.reverse ()
list3 += rem
# reverse the entire list
list3.reverse ()
return list3
A slightly refined by still ugly solution (in Python3.5):
def linear_merge(list1: list, list2: list):
result = []
while len(list1) and len(list2):
result.append((list1 if list1[-1] > list2[-1] else list2).pop(-1))
result += list1 if len(list1) else list2
return result[-1::-1]
def linear_merge(list1, list2):
a= list1 + list2
a.sort()
return a

Categories