I am trying to dynamically get the first and last element from an array.
So, let us suppose the array has 6 elements.
test = [1,23,4,6,7,8]
If I am trying to get the first and last = 1,8, 23,7 and 4,6. Is there a way to get elements in this order?
I looked at a couple of questions Link Link2. I took help of these links and I came up with this prototype..
#!/usr/bin/env python
import numpy
test = [1,23,4,6,7,8]
test1 = numpy.array([1,23,4,6,7,8])
len_test = len(test)
first_list = [0,1,2]
len_first = len(first_list)
second_list = [-1,-2,-3]
len_second = len(second_list)
for a in range(len_first):
print numpy.array(test)[[first_list[a] , second_list[a]]]
print test1[[first_list[a], second_list[a]]]
But this prototype won't scale for if you have more than 6 elements. So, I was wondering if there is way to dynamically get the pair of elements.
Thanks!
I ended here, because I googled for "python first and last element of array", and found everything else but this. So here's the answer to the title question:
a = [1,2,3]
a[0] # first element (returns 1)
a[-1] # last element (returns 3)
How about:
In [10]: arr = numpy.array([1,23,4,6,7,8])
In [11]: [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
Out[11]: [(1, 8), (23, 7), (4, 6)]
Depending on the size of arr, writing the entire thing in NumPy may be more performant:
In [41]: arr = numpy.array([1,23,4,6,7,8]*100)
In [42]: %timeit [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
10000 loops, best of 3: 167 us per loop
In [43]: %timeit numpy.vstack((arr, arr[::-1]))[:,:len(arr)//2]
100000 loops, best of 3: 16.4 us per loop
arr = np.array([1,2,3,4])
arr[-1] # last element
Using Numpy's fancy indexing:
>>> test
array([ 1, 23, 4, 6, 7, 8])
>>> test[::-1] # test, reversed
array([ 8, 7, 6, 4, 23, 1])
>>> numpy.vstack([test, test[::-1]]) # stack test and its reverse
array([[ 1, 23, 4, 6, 7, 8],
[ 8, 7, 6, 4, 23, 1]])
>>> # transpose, then take the first half;
>>> # +1 to cater to odd-length arrays
>>> numpy.vstack([test, test[::-1]]).T[:(len(test) + 1) // 2]
array([[ 1, 8],
[23, 7],
[ 4, 6]])
vstack copies the array, but all the other operations are constant-time pointer tricks (including reversal) and hence are very fast.
>>> test = [1,23,4,6,7,8]
>>> from itertools import izip_longest
>>> for e in izip_longest(test, reversed(test)):
print e
(1, 8)
(23, 7)
(4, 6)
(6, 4)
(7, 23)
(8, 1)
Another option
>>> test = [1,23,4,6,7,8]
>>> start, end = iter(test), reversed(test)
>>> try:
while True:
print map(next, [start, end])
except StopIteration:
pass
[1, 8]
[23, 7]
[4, 6]
[6, 4]
[7, 23]
[8, 1]
You can simply use take method and index of element (Last index can be -1).
arr = np.array([1,2,3])
last = arr.take(-1)
# 3
How about this?
>>> import numpy
>>> test1 = numpy.array([1,23,4,6,7,8])
>>> forward = iter(test1)
>>> backward = reversed(test1)
>>> for a in range((len(test1)+1)//2):
... print forward.next(), backward.next()
...
1 8
23 7
4 6
The (len(test1)+1)//2 ensures that the middle element of odd length arrays is also returned:
>>> test1 = numpy.array([1,23,4,9,6,7,8]) # additional element '9' in the middle
>>> forward = iter(test1)
>>> backward = reversed(test1)
>>> for a in range((len(test1)+1)//2):
... print forward.next(), backward.next()
1 8
23 7
4 6
9 9
Using just len(test1)//2 will drop the middle elemen of odd length arrays.
This does it. Note that with an odd number of elements the one in the middle won't be included.
test = [1, 23, 4, 6, 7, 8, 5]
for i in range(len(test)/2):
print (test[i], test[-1-i])
Output:
(1, 5)
(23, 8)
(4, 7)
How about this:
xs = [1,23,4,6,7,8]
np.array(list(zip(xs[:len(xs)//2], xs[::-1])))
array([[ 1, 8],
[23, 7],
[ 4, 6]])
Assuming the list has a even number of elements, you could do:
test = [1,23,4,6,7,8]
test_rest = reversed(test[:len(test)/2])
for n in len(test_rest):
print [test[n], test_test[n]]
Related
Here's basic problem:
>>> listb = [ 1, 2, 3, 4, 5, 6, 7 ]
>>> slicea = slice(2,5)
>>> listb[slicea]
[3, 4, 5]
>>> lista = listb[slicea]
>>> lista
[3, 4, 5]
>>> listb[slicea] += lista
>>> listb
[1, 2, 3, 4, 5, 3, 4, 5, 6, 7]
listb should be
[1, 2, 6, 8, 10, 6, 7]
But 3, 4, 5 was inserted after 3, 4, 5 not added to it.
tl;dr
I have this code that's not working:
self.lib_tree.item(song)['values'][select_values] = adj_list
self.lib_tree.item(album)['values'][select_values] += adj_list
self.lib_tree.item(artist)['values'][select_values] += adj_list
The full code is this:
def toggle_select(self, song, album, artist):
# 'values' 0=Access, 1=Size, 2=Selected Size, 3=StatTime, 4=StatSize,
# 5=Count, 6=Seconds, 7=SelSize, 8=SelCount, 9=SelSeconds
# Set slice to StatSize, Count, Seconds
total_values = slice(4, 7) # start at index, stop before index
select_values = slice(7, 10) # start at index, stop before index
tags = self.lib_tree.item(song)['tags']
if "songsel" in tags:
# We will toggle off and subtract from selected parent totals
tags.remove("songsel")
self.lib_tree.item(song, tags=(tags))
# Get StatSize, Count and Seconds
adj_list = [element * -1 for element in \
self.lib_tree.item(song)['values'][total_values]]
else:
tags.append("songsel")
self.lib_tree.item(song, tags=(tags))
# Get StatSize, Count and Seconds
adj_list = self.lib_tree.item(song)['values'][total_values] # 1 past
self.lib_tree.item(song)['values'][select_values] = adj_list
self.lib_tree.item(album)['values'][select_values] += adj_list
self.lib_tree.item(artist)['values'][select_values] += adj_list
if self.debug_toggle < 10:
self.debug_toggle += 1
print('artist,album,song:',self.lib_tree.item(artist, 'text'), \
self.lib_tree.item(album, 'text'), \
self.lib_tree.item(song, 'text'))
print('adj_list:',adj_list)
The adj_list has the correct values showing up in debug.
How do I add a list of values to the slice of a list?
The behavior you want is not a feature of any Python built-in type; + with built-in sequences means concatenation, not element-wise addition. But numpy arrays will do what you want, so I'd suggest looking into numpy. Simple example:
>>> import numpy as np
>>> a = np.array([2,3,4], dtype=np.int64)
>>> b = np.array([5,6,7], dtype=np.int64)
>>> a += b
>>> a
array([ 7, 9, 11])
>>> print(a)
[ 7 9 11]
>>> print(a.tolist())
[7, 9, 11]
Note that the output (both repr and str forms) looks a little different from Python lists, but you can convert back to a plain Python list if needed.
I would like to make the following sum given two lists:
a = [0,1,2,3,4,5,6,7,8,9]
b = [2,3,5]
The result should be the sum of the every b element of a like:
b[0] = 2 so the first sum result should be: sum(a[0:2])
b[1] = 3 so the second sum result should be: sum(a[2:5])
b[2] = 5 so the third sum result should be: sum(a[5:10])
The printed result: 1,9,35
You can make use of np.bincount with weights:
groups = np.repeat(np.arange(len(b)), b)
np.bincount(groups, weights=a)
Output:
array([ 1., 9., 35.])
NumPy has a tool to do slice based sum-reduction with np.add.reduceat -
In [46]: np.add.reduceat(a,np.cumsum(np.r_[0,b[:-1]]))
Out[46]: array([ 1, 9, 35])
Hard to compete with the np.bincount solution, but here's another nice way to approach it with np.cumsum:
strides = [0] + np.cumsum(b).tolist() # [0, 2, 5, 10]
stride_slices = zip(strides[:-1], strides[1:]) # [(0, 2), (2, 5), (5, 10)]
[sum(a[s[0]: s[1]]) for s in stride_slices]
# [1, 9, 35]
You mean something like this?
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [2, 3, 5]
def some_function(a, b): # couldnt come up with a name :D
last_index = 0
for i in b:
print(sum(a[last_index:last_index + i]))
last_index += i
some_function(a, b)
You can use a list comprehension with sum:
a=[0,1,2,3,4,5,6,7,8,9]
b=[2,3,5]
r = [sum(a[(k:=sum(b[:i])):k+j]) for i, j in enumerate(b)]
Output:
[1, 9, 35]
I have to get the total sum of a range from an array. However the array range needs to move from one element to another. for example if the array is 1,2,3,4,5,6 and if every two element needs to be added , then it should add 1+2 than 2+3 than 3+4 and so on.
I have tried but not getting right approach. I am sure there is a pythonic way of doing this.
here what I have tried
data = np.arange(0,20,.3)
for i in range (0,len(data)):
for j in range(i,len(data)):
get_range = data[j:5]
get_add = get_range.sum()
print("sum:",get_add)
I have tried to add every 5 element here.
You could use a list comprehension which retrieves a chunks list.
l = [1,2,3,4,5,6]
n = 2
output = [sum(l[i:i + n]) for i in range(0, len(l) - n + 1, 1)]
Output
[3, 5, 7, 9, 11]
There is a numpyic way to do this. It is more memory- and CPU- effective if your input data is big enougth.
import numpy as np
# input array: [1, 2, 3, 4, 5, 6]
data = np.arange(1, 7)
# cumulative sum: [1, 3, 6, 10, 15, 21]
data_cumsum = np.cumsum(data)
# append zero to start: [0, 1, 3, 6, 10, 15, 21]
data_cumsum = np.hstack([0, data_cumsum])
# calculate moving sum
window = 2
moving_sum = data_cumsum[window:] - data_cumsum[:-window]
print(moving_sum)
Output:
[ 3 5 7 9 11]
A minor change will solve the problem
data = np.arange(0,10)
for j in range(0,len(data)-1):
get_range = data[j:j+2] #changed from j to j+2
get_add = get_range.sum()
print("sum:",get_add)
OUTPUT
('sum:', 1)
('sum:', 3)
('sum:', 5)
('sum:', 7)
('sum:', 9)
('sum:', 11)
('sum:', 13)
('sum:', 15)
('sum:', 17)
You can easily condense above steps to form a list comprehension giving the same results with same complexity
[sum(data[j:j+2]) for j in range(0,len(data)-1)]
Another fancy approach could be using sliding_window function
from toolz.itertoolz import sliding_window
map(sum,list(sliding_window(2,list(range(0,10)))))
Output
[1, 3, 5, 7, 9, 11, 13, 15, 17]
I have a function foo that returns an array with the shape (1000, 2)
how can I split it to two arrays a(1000) and b(1000)
I'm looking for something like this:
a;b = foo()
I'm looking for an answer that can easily generalize to the case in which the shape is (1000, 5) or so.
The zip(*...) idiom transposes a traditional more-dimensional Python list:
x = [[1,2], [3,4], [5,6]]
# get columns
a, b = zip(*x) # zip(*foo())
# a, b = map(list, zip(*x)) # if you prefer lists over tuples
a
# (1, 3, 5)
# get rows
a, b, c = x
a
# [1, 2]
Transpose and unpack?
a, b = foo().T
>>> a, b = np.arange(20).reshape(-1, 2).T
>>> a
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
>>> b
array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19])
You can use numpy.hsplit.
x = np.arange(12).reshape((3, 4))
np.hsplit(x, x.shape[1])
This returns a list of subarrays. Note that in the case of a 2d input, the subarrays will be shape (n, 1). Unless you wrap a function around it to squeeze them to 1d:
def split_1d(arr_2d):
"""Split 2d NumPy array on its columns."""
split = np.hsplit(arr_2d, arr_2d.shape[1])
split = [np.squeeze(arr) for arr in split]
return split
a, b, c, d = split_1d(x)
a
# array([0, 4, 8])
d
# array([ 3, 7, 11])
You could just use list comprehensions, e.g.
(a,b)=([i[0] for i in mylist],[i[1] for i in mylist])
To generalise you could use a comprehension within a comprehension:
(a,b,c,d,e)=([row[i] for row in mylist] for i in range(5))
You can do this simply by using zip function like:
def foo(mylist):
return zip(*mylist)
Now call foo with as much dimension as you have in mylist, and it would do the requisite like:
mylist = [[1, 2], [3, 4], [5, 6]]
a, b = foo(mylist)
# a = (1, 3, 5)
# b = (2, 4, 6)
So this is a little nuts, but if you want to assign different letters to each sub-array in your array, and do so for any number of sub-arrays (up to 26 because alphabet), you could do:
import string
letters = list(string.ascii_lowercase) # get all of the lower-case letters
arr_dict = {k: v for k, v in zip(letters, foo())}
or more simply (for the last line):
arr_dict = dict(zip(letters, foo()))
Then you can access each individual element as arr_dict['a'] or arr_dict['b']. This feels a little mad-scientist-ey to me, but I thought it was fun.
For example
X=[5,6,2,3,1]
Y=[7,2,3,4,6]
I sort X:
X=[1,2,3,5,6]
But I want the same relative sort applied to Y so the numbers stay in the same positions relative to each other as before:
Y=[6,3,4,7,2]
I hope this makes sense!
Usually, you do a zip-sort-unzip for this
>>> X = [5,6,2,3,1]
>>> Y = [7,2,3,4,6]
Now sort them together:
>>> sorted(zip(X,Y))
[(1, 6), (2, 3), (3, 4), (5, 7), (6, 2)]
Pair that with a "unzip" (zip(*...))
>>> zip(*sorted(zip(X,Y)))
[(1, 2, 3, 5, 6), (6, 3, 4, 7, 2)]
which you could unpack:
>>> X,Y = zip(*sorted(zip(X,Y)))
>>> X
(1, 2, 3, 5, 6)
>>> Y
(6, 3, 4, 7, 2)
Now you have tuple instead of list objects, but if you really need to, you can convert it back.
As pointed out in the comments, this does introduce a very slight dependence on the second list in the sort: Consider the lists:
X = [1,1,5,7] #sorted already
Y = [2,1,4,6] #Not already sorted.
With my "recipe" above, at the end of the day, you'll get:
X = (1,1,5,7)
Y = (1,2,4,6)
which might be unexpected. To fix that, you could pass a key argument to sorted:
from operator import itemgetter
X,Y = zip(*sorted(zip(X,Y),key=itemgetter(0)))
Demo:
>>> X
[1, 1, 5, 7]
>>> Y
[2, 1, 4, 6]
>>> XX,YY = zip(*sorted(zip(X,Y)))
>>> XX
(1, 1, 5, 7)
>>> YY
(1, 2, 4, 6)
>>> from operator import itemgetter
>>> XX,YY = zip(*sorted(zip(X,Y),key=itemgetter(0)))
>>> XX
(1, 1, 5, 7)
>>> YY
(2, 1, 4, 6)
Another idea:
>>> d = dict(zip(Y, X))
>>> sorted(Y, key=d.get)
[6, 3, 4, 7, 2]
You just use corresponding values in X as keys while sorting Y.
Here is a way to preserve order even if there are duplicate items:
def argsort(seq):
'''
>>> seq = [1,3,0,4,2]
>>> index = argsort(seq)
[2, 0, 4, 1, 3]
Given seq and the index, you can construct the sorted seq:
>>> sorted_seq = [seq[x] for x in index]
>>> assert sorted_seq == sorted(seq)
Given the sorted seq and the index, you can reconstruct seq:
>>> assert [sorted_seq[x] for x in argsort(index)] == seq
'''
return sorted(range(len(seq)), key=seq.__getitem__)
X = (1,1,5,7)
Y = (1,2,4,6)
index = argsort(X)
print([Y[i] for i in index])
yields
[1, 2, 4, 6]
Regarding speed, using_argsort appears to be faster than using_zip or using_dict:
def using_argsort():
index = argsort(X)
return [X[i] for i in index], [Y[i] for i in index]
def using_zip():
return zip(*sorted(zip(X,Y), key = operator.itemgetter(0)))
def using_dict():
d = dict(zip(Y,X))
return sorted(X), sorted(Y, key = d.get)
X = [5,6,2,3,1]*1000
Y = [7,2,3,4,6]*1000
In [18]: %timeit using_argsort()
1000 loops, best of 3: 1.55 ms per loop
In [19]: %timeit using_zip()
1000 loops, best of 3: 1.65 ms per loop
In [21]: %timeit using_dict()
100 loops, best of 3: 2 ms per loop
I'm assuming x and y have the same number of elements. when sorting x, everytime you swap two value, say, x.swap(i,j), you do y.swap(i,j) as well. By the way, I don't know python so this is not python syntax.