change odd elements in list to negative - python

I am trying to change odd elements in a list of int to negative using slicing
l[1::2] = -1 * l[1::2]
However, I encounter the following error:
ValueError: attempt to assign sequence of size 0 to extended slice of size 2

If you wish to uses slices:
>>> a = [1,4,7,8,2]
>>> a[1::2] = [-x for x in a[1::2]]
>>> a
[1, -4, 7, -8, 2]
When assigning to an extended slice like a[1::2], the list/slice on the right hand side must be the same length as the left hand side. In the above, we've mapped to a[1::2] with a list comprehension, so the length is unchanged. If we consider -1 * a[1::2] this yields [] which is of a different length.

Best way would be to do it vectorized with numpy. Without numpy, I don't see a way to do it without creating a new loop. Here you have two examples of how to do it. With and without numpy:
import numpy as np
# vectorized
a = np.arange(10)
a[1::2] *= -1
print(a)
# >>> [ 0 -1 2 -3 4 -5 6 -7 8 -9]
a = [i for i in range(10)]
a = [i if i%2==0 else i*-1 for i in a] # need to loop through list again..
print(a)
# >>> [0, -1, 2, -3, 4, -5, 6, -7, 8, -9]
Edited to fix odd elements to negative, not pos.

Related

getting difference between list values with variable window

>>> jj = [1,3,9,4,5,6,1,2,4,1,7,9,0,4,1,9]
>>> np.diff(jj)
[ 2 6 -5 1 1 -5 1 2 -3 6 2 -9 4 -3 8]
np.diff gives difference between the consecutive numbers. I am looking for difference between every element with a gap of 3 values
input: [1,3,9,4,5,6,1,2,4,1,7,9,0,4,1,9]
difference between the bold values
output : [3,-3,0,-1,-9]
Well, the most straightforward way is to slice for every third number:
>>> import numpy as np
>>> arr = np.array([1,3,9,4,5,6,1,2,4,1,7,9,0,4,1,9])
>>> np.diff(arr[::3])
array([ 3, -3, 0, -1, 9])
Note, if you use a numpy.ndarray then this is fairly space-efficient since arr[::3] creates a view
You still can use np.diff just pass not the whole array but a specific array like this:
np.diff(jj[::3])
First, you can use slicing with step : 3. then use numpy.diff. You can read understanding-slicing
import numpy as np
a = np.array([1,3,9,4,5,6,1,2,4,1,7,9,0,4,1,9])
b = np.diff(a[::3])
print(b)
Output: array([ 3, -3, 0, -1, 9])

Change Numpy array values in-place

Say when we have a randomly generated 2D 3x2 Numpy array a = np.array(3,2) and I want to change the value of the element on the first row & column (i.e. a[0,0]) to 10. If I do
a[0][0] = 10
then it works and a[0,0] is changed to 10. But if I do
a[np.arange(1)][0] = 10
then nothing is changed. Why is this?
I want to change some columns values of a selected list of rows (that is indicated by a Numpy array) to some other values (like a[row_indices][:,0] = 10) but it doesn't work as I'm passing in an array (or list) that indicates rows.
a[x][y] is wrong. It happens to work in the first case, a[0][0] = 10 because a[0] returns a view, hence doing resul[y] = whatever modifies the original array. However, in the second case, a[np.arange(1)][0] = 10, a[np.arange(1)] returns a copy (because you are using array indexing).
You should be using a[0, 0] = 10 or a[np.arange(1), 0] = 10
Advanced indexing always returns a copy as a view cannot be guaranteed.
Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view).
If you replace np.arange(1) with something that returns a view (or equivalent slicing) then you get back to basic indexing, and hence when you chain two views, the change is reflected into the original array.
For example:
import numpy as np
arr = np.arange(2 * 3).reshape((2, 3))
arr[0][0] = 10
print(arr)
# [[10 1 2]
# [ 3 4 5]]
arr = np.arange(2 * 3).reshape((2, 3))
arr[:1][0] = 10
print(arr)
# [[10 10 10]
# [ 3 4 5]]
arr = np.arange(2 * 3).reshape((2, 3))
arr[0][:1] = 10
print(arr)
# [[10 1 2]
# [ 3 4 5]]
etc.
If you have some row indices you want to use, to modify the array you can just use them, but you cannot chain the indexing, e.g:
arr = np.arange(5 * 3).reshape((5, 3))
row_indices = (0, 2)
arr[row_indices, 0] = 10
print(arr)
# [[10 1 2]
# [ 3 4 5]
# [10 7 8]
# [ 9 10 11]
# [12 13 14]]

How to fix the multiple value assignment to the variables in the python code below?

Given a list of unique numbers in python, I need to swap the positions of the maximum and minimum numbers in the list.
Apart from the traditional way of doing by getting the positions of the numbers by for loop, I tried to do that by the in-built python functions and used it directly in the multiple variables assignment method which is shown below.
a = [i for i in range(6, 1, -1)]
print("The original array is =", a) # print's [6, 5, 4, 3, 2]
index_max = a.index(max(a))
index_min = a.index(min(a))
# a[ a.index(max(a)) ], a[ a.index(min(a)) ] = min(a), max(a) #print's [6, 5, 4, 3, 2]
a[index_max], a[index_min] = min(a), max(a) # print's [2, 5, 4, 3, 6]
print("The swapped array is =", a)
Line no.7 doesn't work as it gives the output [6, 5, 4, 3, 2], instead
of [2, 5, 4, 3, 6].
Whereas line no.8 works perfectly!!
According to docummentation of Python:
WARNING: Although the definition of assignment implies
that overlaps between the left-hand side and the right-
hand side are `safe' (e.g., "a, b = b, a" swaps two
variables), overlaps within the collection of assigned-to
variables are not safe! For instance, the following program
prints "[0, 2]":
x = [0, 1]
i = 0
i, x[i] = 1, 2
print x
So the problem is that, in line 7, Python first does
a [a.index(max(a))] = min(a)
Now, a = [2, 5, 4, 3, 2]. After that, Python does
a [a.index(min(a))] = max(a)
But min(a) = 2, and a.index(2) returns 0. So, in the end, a = [6, 5, 4, 3, 2]. That's why assign the index of min and max before swap the variables does work.
Reference:
https://docs.python.org/2.0/ref/assignment.html
Edit: reference to Python 3 as suggested by #chepner:
Although the definition of assignment implies that overlaps between
the left-hand side and the right-hand side are ‘simultaneous’ (for
example a, b = b, a swaps two variables), overlaps within the
collection of assigned-to variables occur left-to-right, sometimes
resulting in confusion. For instance, the following program prints [0,
2]:
x = [0, 1]
i = 0
i, x[i] = 1, 2 # i is updated, then x[i] is updated
print(x)
Reference:
https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
The important here is the order of the operations. When you do:
a[ a.index(max(a)) ], a[ a.index(min(a)) ] = min(a), max(a)
Python do things in that order:
max(a) # >> 6
a.index(max(a)) # >> 0
a[...] = min(a) # >> a[0] = 2
Then, it do the same with the second member:
min(a) # >> 2
a.index(min(a)) # >> 0
a[...] = max(a) # >> a[0] = 6
The bad behaviour is natural, since you changed the index during the operation...

How to sum the values of list to the power of their indices

How do I sum the values of list to the power of their indices in Python 3?
Example:
[3, 0, 2] = 3^1 + 0^2 + 2^3 = 11
The idea is to create a unique index for any possible combination of non-negative numbers in the list. This way, I can use the list to compute an index of something.
Edit: while the question has been answered, I just realized that the method does not create a unique index for any combination of non-negative integers in the list. To do so, assuming a is the number of possible integers, and based in the accepted answer,
sum(a ** i * j for i,j in enumerate(l, 0))
The idea is that each number will increase the index by an amount exponentially proportional to its position in the list. Assuming a=4 (from 0 to 3), the above example becomes
[3, 0, 2] = 4^0*3 + 4^1*0 + 4^2^2 = 35
Where the indices would range from 0 to 4^3-1=63.
Use enumerate to get the index and supply that to sum:
sum(j ** i for i,j in enumerate(l, 1))
Specifying the start argument to enumerate as 1 assures indices will start from 1 (as you want) and not from 0 (the default which you get with a plain enumerate):
>>> l = [3, 0, 2]
>>> sum(j ** i for i,j in enumerate(l, 1))
11
In a functional spirit, you could also utilize map with count from itertools passing in pow as the function to be mapped:
>>> from itertools import count
>>> sum(map(pow, l, count(1)))
11
These pretty much execute in approximately the same time; the generator expression to sum though offers a slight advantage of flexibility.
You can do this with numpy, which is often faster than iterating through lists:
In [1]: import numpy as np
In [2]: l = [0, 3, 4, 1]
In [3]: np.array(l) ** np.arange(len(l))
Out[3]: array([ 1, 3, 16, 1])
In [4]: np.array(l) ** np.arange(1, len(l) + 1)
Out[4]: array([ 0, 9, 64, 1])

Remove elements that appear more often than once from numpy array

The question is, how can I remove elements that appear more often than once in an array completely. Below you see an approach that is very slow when it comes to bigger arrays.
Any idea of doing this the numpy-way? Thanks in advance.
import numpy as np
count = 0
result = []
input = np.array([[1,1], [1,1], [2,3], [4,5], [1,1]]) # array with points [x, y]
# count appearance of elements with same x and y coordinate
# append to result if element appears just once
for i in input:
for j in input:
if (j[0] == i [0]) and (j[1] == i[1]):
count += 1
if count == 1:
result.append(i)
count = 0
print np.array(result)
UPDATE: BECAUSE OF FORMER OVERSIMPLIFICATION
Again to be clear: How can I remove elements appearing more than once concerning a certain attribute from an array/list ?? Here: list with elements of length 6, if first and second entry of every elements both appears more than once in the list, remove all concerning elements from list. Hope I'm not to confusing. Eumiro helped me a lot on this, but I don't manage to flatten the output list as it should be :(
import numpy as np
import collections
input = [[1,1,3,5,6,6],[1,1,4,4,5,6],[1,3,4,5,6,7],[3,4,6,7,7,6],[1,1,4,6,88,7],[3,3,3,3,3,3],[456,6,5,343,435,5]]
# here, from input there should be removed input[0], input[1] and input[4] because
# first and second entry appears more than once in the list, got it? :)
d = {}
for a in input:
d.setdefault(tuple(a[:2]), []).append(a[2:])
outputDict = [list(k)+list(v) for k,v in d.iteritems() if len(v) == 1 ]
result = []
def flatten(x):
if isinstance(x, collections.Iterable):
return [a for i in x for a in flatten(i)]
else:
return [x]
# I took flatten(x) from http://stackoverflow.com/a/2158522/1132378
# And I need it, because output is a nested list :(
for i in outputDict:
result.append(flatten(i))
print np.array(result)
So, this works, but it's impracticable with big lists.
First I got
RuntimeError: maximum recursion depth exceeded in cmp
and after applying
sys.setrecursionlimit(10000)
I got
Segmentation fault
how could I implement Eumiros solution for big lists > 100000 elements?
np.array(list(set(map(tuple, input))))
returns
array([[4, 5],
[2, 3],
[1, 1]])
UPDATE 1: If you want to remove the [1, 1] too (because it appears more than once), you can do:
from collections import Counter
np.array([k for k, v in Counter(map(tuple, input)).iteritems() if v == 1])
returns
array([[4, 5],
[2, 3]])
UPDATE 2: with input=[[1,1,2], [1,1,3], [2,3,4], [4,5,5], [1,1,7]]:
input=[[1,1,2], [1,1,3], [2,3,4], [4,5,5], [1,1,7]]
d = {}
for a in input:
d.setdefault(tuple(a[:2]), []).append(a[2])
d is now:
{(1, 1): [2, 3, 7],
(2, 3): [4],
(4, 5): [5]}
so we want to take all key-value pairs, that have single values and re-create the arrays:
np.array([k+tuple(v) for k,v in d.iteritems() if len(v) == 1])
returns:
array([[4, 5, 5],
[2, 3, 4]])
UPDATE 3: For larger arrays, you can adapt my previous solution to:
import numpy as np
input = [[1,1,3,5,6,6],[1,1,4,4,5,6],[1,3,4,5,6,7],[3,4,6,7,7,6],[1,1,4,6,88,7],[3,3,3,3,3,3],[456,6,5,343,435,5]]
d = {}
for a in input:
d.setdefault(tuple(a[:2]), []).append(a)
np.array([v for v in d.itervalues() if len(v) == 1])
returns:
array([[[456, 6, 5, 343, 435, 5]],
[[ 1, 3, 4, 5, 6, 7]],
[[ 3, 4, 6, 7, 7, 6]],
[[ 3, 3, 3, 3, 3, 3]]])
This is a corrected, faster version of Hooked's answer. count_unique counts the number of the number of occurrences for each unique key in keys.
import numpy as np
input = np.array([[1,1,3,5,6,6],
[1,1,4,4,5,6],
[1,3,4,5,6,7],
[3,4,6,7,7,6],
[1,1,4,6,88,7],
[3,3,3,3,3,3],
[456,6,5,343,435,5]])
def count_unique(keys):
"""Finds an index to each unique key (row) in keys and counts the number of
occurrences for each key"""
order = np.lexsort(keys.T)
keys = keys[order]
diff = np.ones(len(keys)+1, 'bool')
diff[1:-1] = (keys[1:] != keys[:-1]).any(-1)
count = np.where(diff)[0]
count = count[1:] - count[:-1]
ind = order[diff[1:]]
return ind, count
key = input[:, :2]
ind, count = count_unique(key)
print key[ind]
#[[ 1 1]
# [ 1 3]
# [ 3 3]
# [ 3 4]
# [456 6]]
print count
[3 1 1 1 1]
ind = ind[count == 1]
output = input[ind]
print output
#[[ 1 3 4 5 6 7]
# [ 3 3 3 3 3 3]
# [ 3 4 6 7 7 6]
# [456 6 5 343 435 5]]
Updated Solution:
From the comments below, the new solution is:
idx = argsort(A[:, 0:2], axis=0)[:,1]
kidx = where(sum(A[idx,:][:-1,0:2]!=A[idx,:][1:,0:2], axis=1)==0)[0]
kidx = unique(concatenate((kidx,kidx+1)))
for n in arange(0,A.shape[0],1):
if n not in kidx:
print A[idx,:][n]
> [1 3 4 5 6 7]
[3 3 3 3 3 3]
[3 4 6 7 7 6]
[456 6 5 343 435 5]
kidx is a index list of the elements you don't want. This preserves rows where the first two inner elements do not match any other inner element. Since everything is done with indexing, it should be fast(ish), though it requires a sort on the first two elements. Note that original row order is not preserved, though I don't think this is a problem.
Old Solution:
If I understand it correctly, you simply want to filter out the results of a list of lists where the first element of each inner list is equal to the second element.
With your input from your update A=[[1,1,3,5,6,6],[1,1,4,4,5,6],[1,3,4,5,6,7],[3,4,6,7,7,6],[1,1,4,6,88,7],[3,3,3,3,3,3],[456,6,5,343,435,5]], the following line removes A[0],A[1] and A[4]. A[5] is also removed since that seems to match your criteria.
[x for x in A if x[0]!=x[1]]
If you can use numpy, there is a really slick way of doing the above. Assume that A is an array, then
A[A[0,:] == A[1,:]]
Will pull out the same values. This is probably faster than the solution listed above if you want to loop over it.
Why not create another array to hold the output?
Iterate through your main list and for each i check if i is in your other array and if not append it.
This way, your new array will not contain more than one of each element

Categories