Creating New Array when Second Array is > 0 - python

I'm running Python 2.7.
I have an array called "altitude" with the following points
[0,1,2,3,4,5,6,7,8,9]
I also have an array called "arming_pin"
[0,0,0,0,0,0,1,1,1,1]
In my program when arming_pin is greater than zero I would like to use the "altitude" array data points and ignore the previous points when "arming_pin" was = to 0. I would like to call this new array "altitude_new". The "altitude_new" array would look like:
[6,7,8,9]
How can I do create this new array in python? Using a conditional statement of some sort?

You can use zip function within a list comprehension to filter your array :
>>> f=[0,1,2,3,4,5,6,7,8,9]
>>> sec=[0,0,0,0,0,0,1,1,1,1]
>>>
>>> [i for i,j in zip(f,sec) if j]
[6, 7, 8, 9]
You can also use itertools.compress Which is more efficient when you are dealing with larger list :
>>> from itertools import compress
>>> list(compress(f,sec))
[6, 7, 8, 9]
Or use numpy.compress:
>>> import numpy as np
>>> np.compress(sec,f)
array([6, 7, 8, 9])

You can also use the compress method from itertools module, this way:
>>> import itertools as it
>>> l1 = [0,1,2,3,4,5,6,7,8,9]
>>> l2 = [0,0,0,0,0,0,1,1,1,1]
>>> list(it.compress(l1,l2))
[6, 7, 8, 9]

altitude_new=[]
for i in range(len(arming_pin)):
if arming_pin[i] == 1:
altitude_new.append(altitude[i])
one line list comprehension:
altitude_new = [altitude[i] for i in range(len(arming_pin)) if arming_pin[i]]
night shade's comment is now more succinct [j for i,j in enumerate(altitude) if arming_pin[i]]

This is my solution, is meant to be easy to understand for people not accustomed to list comprehension.
altitude = [0,1,2,3,4,5,6,7,8,9]
arming_pin = [0,0,0,0,0,0,1,1,1,1]
altitude_new = []
idx = 0 # track the indices
for item in arming_pin:
if item > 0:
altitude_new.append(altitude[idx])
idx += 1
print altitude_new
>>> [6, 7, 8, 9]

Related

Why lists cannot be indexed with a list of indexes?

I am asking this question related to this one:
Access multiple elements of list knowing their index
Basically if you have a list and want to get several elements you cannot just pass a list of indexes.
Example:
a = [-2,1,5,3,8,5,6]
b = [1,2,5] # list of indexes
a[b] #this doesn't work
# expected output: [1,5,5]
To solve this problem several options are proposed in the linked question:
Using list comprehension:
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
c = [a[i] for i in b]
Using operator.itemgetter:
from operator import itemgetter
a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
print itemgetter(*b)(a)
or using numpy arrays (which DO accept indexing with lists)
import numpy as np
a = np.array([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
print list(a[b])
My question is: Why normal lists don't accept this? This will not conflict the normal indexing [start:end:step] and will provide another way of accessing list elements without using external libraries.
I don't intend this question to attract opinion based answers but rather to know if there is an specific reason why this feature is not available in Python, or if it will be implemented in a future.
Another way we can get the expected output, and it might can be implemented into python function related with list.
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
def getvalues(original_list, indexes_list):
new_list = []
for i in indexes_list:
new_list.append(original_list[i])
return new_list
result = getvalues(a, b)
print(result)
A simple and easy approach to do it can be done in a list comprehension:
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
multi_index = lambda l1, l2: [l1[i] for i in l2]
>>> print(multi_index(a,b))
[1, 5, 5]

Python 2D list slice

I looked around and could not find anything this specific, so here goes:
I have a list of lists:
S = [[3,4],[6,7],[10,12]]
and I would like to add the 0th index of the ith index element and on to the end of another list:
R = [5,6,7]
Normally with a 1D list I could say:
R = R + S[i:]
and take all of the elements from the ith index on, but I want the 0th index of the ith index of a 2D S. If we started at i = 1 I would end up with:
R = [5,6,7,6,10]
Also, I don't want to use for loops I want a list slice method that will work (if there is one) because it needs to be within a certain bound.
You can use zip to transpose the matrix:
>>> S
[[3, 4], [6, 7], [10, 12]]
>>> zip(*S)
[(3, 6, 10), (4, 7, 12)]
Then slice the transposition:
>>> j=0
>>> i=1
>>> zip(*S)[j][i:]
(6, 10)
A tuple is iterable, so concatenation will work with a list:
>>> R = [5,6,7]
>>> R+=zip(*S)[j][i:]
>>> R
[5, 6, 7, 6, 10]
As #jonrsharpe mentioned, numpy will do the trick for you:
import numpy as np
# Create two arrays
S = np.asarray([[3,4],[6,7],[10,12]])
R = np.asarray([5, 6, 7])
# Slice the S array
i = 1
sliced_S = S[i:, 0]
# Concatenate the arrays
R = np.concatenate((R, sliced_S))
Have a look at numpy's impressive documentation and indexing in particular.

concatenate an arbitrary number of lists in a function in Python

I hope to write the join_lists function to take an arbitrary number of lists and concatenate them. For example, if the inputs are
m = [1, 2, 3]
n = [4, 5, 6]
o = [7, 8, 9]
then we I call print join_lists(m, n, o), it will return [1, 2, 3, 4, 5, 6, 7, 8, 9]. I realize I should use *args as the argument in join_lists, but not sure how to concatenate an arbitrary number of lists. Thanks.
Although you can use something which invokes __add__ sequentially, that is very much the wrong thing (for starters you end up creating as many new lists as there are lists in your input, which ends up having quadratic complexity).
The standard tool is itertools.chain:
def concatenate(*lists):
return itertools.chain(*lists)
or
def concatenate(*lists):
return itertools.chain.from_iterable(lists)
This will return a generator which yields each element of the lists in sequence. If you need it as a list, use list: list(itertools.chain.from_iterable(lists))
If you insist on doing this "by hand", then use extend:
def concatenate(*lists):
newlist = []
for l in lists: newlist.extend(l)
return newlist
Actually, don't use extend like that - it's still inefficient, because it has to keep extending the original list. The "right" way (it's still really the wrong way):
def concatenate(*lists):
lengths = map(len,lists)
newlen = sum(lengths)
newlist = [None]*newlen
start = 0
end = 0
for l,n in zip(lists,lengths):
end+=n
newlist[start:end] = list
start+=n
return newlist
http://ideone.com/Mi3UyL
You'll note that this still ends up doing as many copy operations as there are total slots in the lists. So, this isn't any better than using list(chain.from_iterable(lists)), and is probably worse, because list can make use of optimisations at the C level.
Finally, here's a version using extend (suboptimal) in one line, using reduce:
concatenate = lambda *lists: reduce((lambda a,b: a.extend(b) or a),lists,[])
One way would be this (using reduce) because I currently feel functional:
import operator
from functools import reduce
def concatenate(*lists):
return reduce(operator.add, lists)
However, a better functional method is given in Marcin's answer:
from itertools import chain
def concatenate(*lists):
return chain(*lists)
although you might as well use itertools.chain(*iterable_of_lists) directly.
A procedural way:
def concatenate(*lists):
new_list = []
for i in lists:
new_list.extend(i)
return new_list
A golfed version: j=lambda*x:sum(x,[]) (do not actually use this).
You can use sum() with an empty list as the start argument:
def join_lists(*lists):
return sum(lists, [])
For example:
>>> join_lists([1, 2, 3], [4, 5, 6])
[1, 2, 3, 4, 5, 6]
Another way:
>>> m = [1, 2, 3]
>>> n = [4, 5, 6]
>>> o = [7, 8, 9]
>>> p = []
>>> for (i, j, k) in (m, n, o):
... p.append(i)
... p.append(j)
... p.append(k)
...
>>> p
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
This seems to work just fine:
def join_lists(*args):
output = []
for lst in args:
output += lst
return output
It returns a new list with all the items of the previous lists. Is using + not appropriate for this kind of list processing?
Or you could be logical instead, making a variable (here 'z') equal to the first list passed to the 'join_lists' function
then assigning the items in the list (not the list itself) to a new list to which you'll then be able add the elements of the other lists:
m = [1, 2, 3]
n = [4, 5, 6]
o = [7, 8, 9]
def join_lists(*x):
z = [x[0]]
for i in range(len(z)):
new_list = z[i]
for item in x:
if item != z:
new_list += (item)
return new_list
then
print (join_lists(m, n ,o)
would output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Average List from a List of Lists - Is there a more efficient way?

I have a list of lists named 'run'. I am creating an average of those lists using this section of my code:
ave = [0 for t in range(s)]
for t in range(s):
z = 0
for i in range(l):
z = z + run[i][t]
#Converted values to a string for output purposes
# Added \n to output
ave[t]= ((str(z / l) + "\n"))
Much to my surprise, this code worked the first time that I wrote it. I'm now planning on working with much larger lists and many more values, and it's possible that performance issues will come into play. Is this method of writing an average inefficient in its use of computational resources, and how could I write code that was more efficient?
List comprehensions may be more efficient.
>>> run = [[1, 2, 3, 4, 5], [6, 7, 8, 9], [10, 11, 12, 13]]
>>> [sum(elem)/len(elem) for elem in zip(*run)]
[5.666666666666667, 6.666666666666667, 7.666666666666667, 8.666666666666666]
Alternatively, you could try map()
>>> list(map(lambda x: sum(x)/len(x), zip(*run)))
[5.666666666666667, 6.666666666666667, 7.666666666666667, 8.666666666666666]
You can improve efficiency by having Python do more of the work for you with efficient built-in functions and list comprehensions:
averages = [sum(items) / len(run) for items in zip(*run)]
import numpy as np
ave = [np.avg(col) for col in zip(*run)]
OR
ave = [sum(col)/len(col) for col in zip(*run)]
I entered this question looking for the following, which is dumb but as it does not use zip it does not ignore any value.
If you have a numerical list of lists with different lengths and want to find the average list
import numpy as np
def my_mean(list_of_lists):
maxlen = max([len(l) for l in list_of_lists])
for i in range(len(list_of_lists)):
while len(list_of_lists[i]) < maxlen:
list_of_lists[i].append(np.nan)
return np.nanmean(list_of_lists, axis=0)
aaa = [1, 2, 3]
bbb = [1, 2, 3, 5]
ccc = [4, 5, 6, 5, 10]
lofl = [aaa, bbb, ccc]
print(my_mean(lofl))
gives
[ 2. 3. 4. 5. 10.]

How to add an integer to each element in a list?

If I have list=[1,2,3] and I want to add 1 to each element to get the output [2,3,4],
how would I do that?
I assume I would use a for loop but not sure exactly how.
new_list = [x+1 for x in my_list]
The other answers on list comprehension are probably the best bet for simple addition, but if you have a more complex function that you needed to apply to all the elements then map may be a good fit.
In your example it would be:
>>> map(lambda x:x+1, [1,2,3])
[2,3,4]
>>> mylist = [1,2,3]
>>> [x+1 for x in mylist]
[2, 3, 4]
>>>
list-comprehensions python.
if you want to use numpy there is another method as follows
import numpy as np
list1 = [1,2,3]
list1 = list(np.asarray(list1) + 1)
Edit: this isn't in-place
Firstly don't use the word 'list' for your variable. It shadows the keyword list.
The best way is to do it in place using splicing, note the [:] denotes a splice:
>>> _list=[1,2,3]
>>> _list[:]=[i+1 for i in _list]
>>> _list
[2, 3, 4]
>>> [x.__add__(1) for x in [1, 3, 5]]
3: [2, 4, 6]
My intention here is to expose if the item in the list is an integer it supports various built-in functions.
Python 2+:
>>> mylist = [1,2,3]
>>> map(lambda x: x + 1, mylist)
[2, 3, 4]
Python 3+:
>>> mylist = [1,2,3]
>>> list(map(lambda x: x + 1, mylist))
[2, 3, 4]
import numpy as np
np.add([1, 2, 3], 1).tolist()
which gives
[2, 3, 4]
Came across a not so efficient, but unique way of doing it. So sharing it across.And yes it requires extra space for another list.
from operator import add
test_list1 = [4, 5, 6, 2, 10]
test_list2 = [1] * len(test_list1)
res_list = list(map(add, test_list1, test_list2))
print(test_list1)
print(test_list2)
print(res_list)
#### Output ####
[4, 5, 6, 2, 10]
[1, 1, 1, 1, 1]
[5, 6, 7, 3, 11]
list = [1,2,3,4,5]
for index in range(len(list)):
list[index] = list[index] +1
print(list)
Just in case anyone was looking for a solution that only uses built-ins and no lambdas:
from functools import partial
from operator import add
my_list = range(1, 4) # list(my_list) #=> [1, 2, 3]
my_list_plus_one = list(map(partial(add, 1), my_list) #=> [2, 3, 4]
Many of the answers above are very good. I've also seen some weird answers that will do the job. Also, the last answer seen was through a normal loop. This willingness to give answers leads me to itertools and numpy, which will do the same job in a different way.
Here I present different ways to do the job, not answered above.
import operator
import itertools
x = [3, 5, 6, 7]
integer = 89
"""
Want more vairaint can also use zip_longest from itertools instead just zip
"""
#lazy eval
a = itertools.starmap(operator.add, zip(x, [89] * len(x))) # this is not subscriptable but iterable
print(a)
for i in a:
print(i, end = ",")
# prepared list
a = list(itertools.starmap(operator.add, zip(x, [89] * len(x)))) # this returns list
print(a)
# With numpy (before this, install numpy if not present with `pip install numpy`)
import numpy
res = numpy.ones(len(x), dtype=int) * integer + x # it returns numpy array
res = numpy.array(x) + integer # you can also use this, infact there are many ways to play around
print(res)
print(res.shape) # prints structure of array, i.e. shape
# if you specifically want a list, then use tolist
res_list = res.tolist()
print(res_list)
Output
>>> <itertools.starmap object at 0x0000028793490AF0> # output by lazy val
>>> 92,94,95,96, # output of iterating above starmap object
>>> [92, 94, 95, 96] # output obtained by casting to list
>>> __
>>> # |\ | | | |\/| |__| \ /
>>> # | \| |__| | | | |
>>> [92 94 95 96] # this is numpy.ndarray object
>>> (4,) # shape of array
>>> [92, 94, 95, 96] # this is a list object (doesn't have a shape)
My sole reason to highlight the use of numpy is that one should always do such manipulations with libraries like numpy because it is performance efficient for very large arrays.

Categories

Resources