Creating list in a for loop - python

Wondering if someone can help me with a small problem bit of code I have.
list1 = [1,2,4]
dz = 0.5
k = max(list1)/dz
print('k =',k)
list1_diff = np.insert(np.diff(list1),0,1)
for item in list1_diff:
#Number of times to repeat number
repeats = item/dz
vec = [np.random.normal(0,1)]*int(repeats)
print(vec)
this produces
[-0.7014481088047718, -0.7014481088047718]
[3.1264015795601274, 3.1264015795601274]
[0.44017976879654314, 0.44017976879654314, 0.44017976879654314, 0.44017976879654314]
Which is doing sort of the right thing, but I want the output of the loop to be these three lists as one single list. So it should be
[-0.7014481088047718, -0.7014481088047718, 3.1264015795601274, 3.1264015795601274, 0.44017976879654314, 0.44017976879654314, 0.44017976879654314, 0.44017976879654314]

you're not dumb. If I got you right, you want to have one list with repeated random numbers according to your formula.
You would just have to modify your code a small bit, like this:
list1 = [1,2,4]
dz = 0.5
k = max(list1)/dz
print('k =',k)
list1_diff = np.insert(np.diff(list1),0,1)
# create your empty result list, where you add the random numbers in the loop
vec= list()
for item in list1_diff:
# Number of times to repeat number
repeats = item/dz
# add the new random number with it's repeats to the vec list
# using extend
vec.extend([np.random.normal(0,1)]*int(repeats))
# print the result outside the loop, after it has been constructed
print(vec)

try this one :
import numpy as np
list1 = [1,2,4]
dz = 0.5
k = max(list1)/dz
print('k =',k)
list1_diff = np.insert(np.diff(list1),0,1)
final_list=[]
for item in list1_diff:
#Number of times to repeat number
repeats = item/dz
vec = [np.random.normal(0,1)]*int(repeats)
final_list += vec
print(final_list)

this should do the job:
import numpy as np
list1 = [1,2,4]
dz = 0.5
k = max(list1)/dz
print(f'k = {k}')
lst = [[np.random.normal(0,1)]*int(item/dz) for item in np.insert(np.diff(list1),0,1)]
flatten = lambda l: [item for sublist in l for item in sublist]
print(flatten(lst))
output:
k = 8.0
[-1.1762058341816053, -1.1762058341816053, -1.0599923573472354, -1.0599923573472354, 0.6374252888036466, 0.6374252888036466, 0.6374252888036466, 0.6374252888036466]
Heres what happened
list comprehension that creates a list full of output (mainly what you did)
flatten function applied to list
note that you can also use extend(), i was going to add it in but another answer beat me to it

Pythons lists have an inbuilt function for this:
list_name.extend([])
For example,
list_name = [1, 2, 3]
list_name.extend([4, 5, 6])
print(sample_list)
[1, 2, 3, 4, 5, 6]
So python extend function extends the list with another list. It does not appends it!

Related

Take the position of the indexes that meets a condiion

I have two lists,
In the first list I have all the information:
list1 = ['node1=6d', 'node2=10d', 'node3=5d']
In the second I just have the days:
list 2 = [6, 10, 5]
Is there a way to take the position from the indexes of the second one, that are <=7 ? (For example) and then print those with the same position of the list1?
Example:
Values of list2 that are <= 7:
Position 0, 2
Then print from list one those values with the position 0, 2
Output should be:
['node1=6d', 'node3=5d']
Original answer:
from operator import itemgetter
idx = [i for i, n in enumerate(list2) if n <= 7]
result = itemgetter(*idx)(list1)
print(result)
To get the list item indices according to a condition, you can just use a list comprehension:
idx = [i for i, n in enumerate(list2) if n <= 7]
If you wish to retrieve the values using the indices, you have several options, some of which are:
Using itemgetter:
Return a callable object that fetches item from its operand using the operand’s getitem() method. If multiple items are specified, returns a tuple of lookup values.
[Python Documentation]
from operator import itemgetter
result = itemgetter(*idx)(list1)
print(result)
('node1=6d', 'node3=5d')
Using a list comprehension again:
result = [list1[i] for i in idx]
Directly invoking __getitem__ (This is not a best practice!):
Called to implement evaluation of self[key]...
[Python Documentation]
result = list(map(list1.__getitem__, idx))
Bonus: If you wish to use numpy at some point, this would be a convenient solution:
import numpy as np
# Creating numpy arrays
list1 = np.array(['node1=6d', 'node2=10d', 'node3=5d'])
list2 = np.array([6, 10, 5])
# Getting the indices
idx = np.where(list2 <= 7)
# Getting all the values at once and converting the array into a list
result = list(list1[idx])
You can try this:
days_condition = 7
index_output = [index for index,val in enumerate(list_2) if val<=days_condition]
"Positions: "+",".join(map(str, index_output))
## you can access the list1 using the index_output
[list1[index] for index in index_output]
output:
'Positions 0,2'
['node1=6d', 'node3=5d']
You can use zip()
res = [x for x, y in zip(list1, list2) if y < 8]
print(res)
#['node1=6d', 'node3=5d']

Store multiple values in arrays Python

I'm doing a code that needs to store the values of the inputs in two arrays. I'm gonna do a example.
INPUTS: 1,2,3,4,5,6,7,8
Array1= []
Array2= []
What I want to make is store the first value of the input in the array1 and the second in the array2. The final result will be this
Array1=[1,3,5,7]
Array2=[2,4,6,8]
Is possible to do that in python3? Thank you
I tried something like this but doesn't work
arr1,arr2 = list(map(int, input().split()))
You can use the following:
l = [int(x) for x in input().split(',')]
array_1 = l[::2]
array_2 = l[1::2]
So, I assume that you can get the inputs into a list or 'array' using the split? It would be nice to somehow 'map' the values, and numpy probably would offer a good solution. Though, here is a straight forward work;
while INPUTS:
ARRAY1.append(INPUTS.pop())
if INPUTS:
ARRAY2.append(INPUTS.pop())
your attempt:
arr1,arr2 = list(map(int, input().split()))
is trying to unpack evenly a list of 8 elements in 2 elements. Python can unpack 2 elements into 1 or 2, or even use iterable unpacking like:
>>> arr1,*arr2 = [1,2,3,4]
>>> arr2
[2, 3, 4]
but as you see the result isn't what you want.
Instead of unpacking, use a list of lists, and a modulo to compute the proper destination, in a loop:
lst = list(range(1,9)) # or list(map(int, input().split())) in interactive string mode
arrays = [[],[]]
for element in lst:
arrays[element%2].append(element)
result:
[[2, 4, 6, 8], [1, 3, 5, 7]]
(change the order with arrays[1-element%2])
The general case would be to yield the index depending on a condition:
arrays[0 if some_condition(element) else 1].append(element)
or with 2 list variables:
(array1 if some_condition(element) else array2).append(element)
There is my solution in a Class ;)
class AlternateList:
def __init__(self):
self._aList = [[],[]]
self._length = 0
def getItem(self, index):
listSelection = int(index) % 2
if listSelection == 0:
return self._aList[listSelection][int(index / 2)]
else:
return self._aList[listSelection][int((index -1) / 2)]
def append(self, item):
# select list (array) calculating the mod 2 of the actual length.
# This alternate between 0 and 1 depending if the length is even or odd
self._aList[int(self._length % 2)].append(item)
self._length += 1
def toList(self):
return self._aList
# add more methods like pop, slice, etc
How to use:
inputs = ['lemon', 'apple', 'banana', 'orange']
aList = AlternateList()
for i in inputs:
aList.append(i)
print(aList.toList()[0]) # prints -> ['lemon', 'banana']
print(aList.toList()[1]) # prints -> ['apple', 'orange']
print(aList.getItem(3)) # prints -> "orange" (it follow append order)
The pythonic way
Here I have taken some assumptions according to above question:
Given inputs only contain integers.
odd and even are two arrays which contain odd numbers and even numbers respectively.
odd, even = list(), list()
[even.append(i) if i % 2 == 0 else odd.append(i) for i in list(map(int, input().split()))]
print("Even: {}".format(even))
print("Odd: {}".format(odd))

How do I keep the order of sorted numbers in a list the same in Python

I have a function in which:
Given a list of Python values xs and a non-negative integer n, construct and return a copy of xs but with each value replicated n times. Do NOT modify the original list 'xs'
To do this, I created some small code that multiplied the list xs and then sorted it.
def replicate(xs,n):
xscopy = sorted(n * xs)
return xscopy
This code will result in a function input like "replicate([1,2,2,3],2)" to output as [1,1,2,2,2,2,3,3] which is correct. Note how the correct output has the numbers' places matching.
However, when a negative number is in the list, the 'sort' function sees the negative number as smaller than the positive numbers and shifts the position of the negative number from where it was originally on the list.
For example: replicate([1,-1,2,1],2) outputs to [-1,-1,1,1,1,1,2,2] rather than, the correct version, [1,1,-1,-1,2,2,1,1].
Notice how the negative 1 shifted?
I am required to use a loop of some sort (while or for) for this task and I can't figure out how I could incorporate a loop that would both preserve the positions of the numbers and append the numbers properly into a new list (a new list that contains both the original xs, and the duplicates, in the same order as the original.
EDIT: I should add that list comprehension is restricted for this task
You could just use a nested list comprehension if you want to keep the order of the elements from the original list, this will take each element from the list xs, repeat it n times and then go for the next element and so on:
xs = [1,-1,2,1]
n = 2
[x for x in xs for _ in range(n)]
# [1, 1, -1, -1, 2, 2, 1, 1]
xs = [1,2,3]
n = 2
[x for x in xs for _ in range(n)]
# [1, 1, 2, 2, 3, 3]
def replicate(xs, n):
return [item for item in xs for repeat in range(n)]
You don't need to sort it. For each number in the list, loop n times and add it to a new list, so you preserve the original list and still get what you wanted.
def replicate(xs,n):
result = []
for num in xs:
for _ in range(n):
result.append(num)
return result
A cleaner way would be using list comprehension return [num for num in xs for _ in range(n)]
Either way, output of replicate([1,-1,2,1],2) is [1, 1, -1, -1, 2, 2, 1, 1]
You can create a single-element list, and then multiply it. Once you have an n-element list, you can extend() the result list with that portion of the result.
result = []
for item in xs:
nitems = [item] * n
result.extend(nitems)
The functools.reduce function can be used for this:
import functools
return functools.reduce((lambda a,b: a + [b]*n), xs, [])
The sum builtin can do something similar:
return sum( [ [x]*n for x in xs], [])
The itertools.chain function can paste together a bunch of iterables, so you could just multiply the values into a bunch of sub-lists and pass them to it:
import itertools
return list(itertools.chain(*[ [x]*n for x in xs ]))
Or, without the splat (*) operator:
import itertools
return list(itertools.chain.from_iterable([[x]*n for x in xs])
Or, you could zip the original list against itself, then flatten those tuples. (This would be good for long lists, especially if you could just return the iterable instead of a list):
import itertools
return list(itertools.chain.from_iterable(zip(*[iter(xs) for _ in range(n)])))

How to create list of all possible lists with n elements consisting of integers between 1 and 10?

I'm trying to create a set of test cases for a project I'm working on, and I'd like to create all possible test cases and iterate through them (quick program, shouldn't take long). The test cases should all be a list of length 1-4 and each item on the list should be an integer between 0-10, inclusive. The first item on the list should be 0. The set of lists would then be:
[0]
[0,0]
[0,1]
[0,2]
[0,3]
...
[0,10]
[0,0,0]
[0,0,1]
[0,0,2]
[0,0,3]
...
[0,1,0]
[0,1,1]
[0,1,2]
...
[0,10,10]
...
[0,10,10,10]
This is what I have so far, but it's not outputting the correct lists:
test_list = [0]
for length in range(2, 5):
while len(test_list) < length:
test_list.append(0)
for position in range(1, length):
for digit in range (0, 11):
test_list[position] = digit
print test_list
or you could generate the lists with a generator; this way you would not have the whole list in memory:
from itertools import product
def gen():
yield [0]
for i in range(11):
yield [0, i]
for i, j in product(range(11), range(11)):
yield [0, i, j]
for i, j, k in product(range(11), range(11), range(11)):
yield [0, i, j, k]
for item in gen():
print(item)
this seems pretty readable to me but is not extensible (in case you need longer lists) as other answers here.
therefore here the version where the length of the list is tweakable:
from itertools import product
def gen(length):
for l in range(length):
for tpl in product(range(11), repeat=l):
yield (0,) + tpl
for item in gen(length=4):
print(item)
this version now returns tuples and not lists. in case this matters you can surrout the return values with list().
I would use itertools.product on lists of size 2, 3, 4 in a nested loop
import itertools
test_list = [0]
for i in range(1,4):
args = [list(range(0,11))] *i
test_list += [[0]+list(x) for x in itertools.product(*args)]
# display list
for t in test_list:
print(t)
A memory efficient one-liner :
import itertools
size = 4
for x in map(list, itertools.chain(*(itertools.product([0], *[range(11)]*i) for i in range(size)))):
print(x)
You can modify 4 with any other list size :)

Count elements in nested list

The following python code should make it clear what i'd like to accomplish.
# Say I have the following list and I want to keep count of 1's while going through each nested list
L = [[1,1,0,0,0,1],[1,1,0,0,0,0],[0,0,0,0,0,1],[1,1,1,1,1,1]]
# So I'd like to get a list containing [3, 5, 6, 12]
# I tried to find a compact way of doing this by mapping this list into a another list like such
T = [L[:i].count(1) for i in range(len(L))]
# >>> [0, 0, 0, 0]
# But this doesn't work so how to count occurances for nested lists?
# Is there a compact way of doing this (maybe with Lambda functions)?
# I'd like to avoid using a function like:
def Nested_Count():
Result = []
count = 0
for i in L:
count += i.count(1)
Result.append(count)
return Result
# >>> [3, 5, 6, 12]
Please let me know if it's possible or not to have a more compact code to do this.
Thanks!
[sum([x.count(1) for x in L[:i]]) for i in range(1, len(L) + 1)]
should do what you want.
Use sum and a list comprehension.
L = [[1,1,0,0,0,1],[1,1,0,0,0,0],[0,0,0,0,0,1],[1,1,1,1,1,1]]
L2 = [sum(x) for x in L]
T = [sum(L2[:x+1]) for x in xrange(len(L2))]

Categories

Resources