Invert negative values in a list - python

I am trying to convert a list that contains negative values, to a list of non-negative values; inverting the negative ones. I have tried abs but it didn't work.
My input is
x = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
How can I make it into this format as I am trying calculate the area
x = [10,9,8,7,6,5,4,3,2,1,0,1,2,3,4,5,6,7,8,9,10]

Try a list comprehension:
x2 = [abs(k) for k in x]

Your attempt didn't work because abs() takes an integer, not a list. To do this, you'll have to either loop through the list:
x = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
for i in range(len(x)):
x[i] = abs(x[i])
Or you can use list comprehension, which is shorter:
x = [abs(i) for i in x]
Or simply use the built-in map function, which is even shorter :)
x = list(map(abs, x))
Hope this helps!

The simple pythonic way is the list comprehension above but if you're using Numpy for anything else you could do:
x2 = numpy.abs(x)
with no need to convert or do any looping.

what you want is to use the absolute value (|x| = x if x > 0, |x| = -x if x < 0)
for index in range(len(x)):
x[index] = x[index] if x[index] > 0 else -x[index]

This is a wrong answer to your question, but this is what I came here looking for. This is how to invert all the numbers in your list using operator.neg; i.e. also positives to negatives.
import operator
x = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
x = list(map(operator.neg, x))
It returns:
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Or you can do a list comprehension of course:
x = [-xi for xi in x]

Related

Python equivalent to replace() in R

Is there a powerful replace function in Python, something equivalent to replace(x, l, y) in R?
e.g.
x = [0,0,0,0,0,0,0,0,0, 0]
l = [True,False,True,True,False,False,False,False,True, False]
y = [5, 6, 7, 8]
The number of values in y matches the number of True in l. In R,
replace(x, l, y) will have x replaced by y corresponding to the True positions in l.
Is there a similar function in Python I can call? If not, any suggestions how to make it working?
Thanks much in advance!
Since the number of Trues and the number of elements in y are the same, we can a generator over y, and then use a list comprehension to build the result. We extract from y if the corresponding element in l is True, else we extract from x:
iter_y = iter(y)
[next(iter_y) if l_item else x_item for l_item, x_item in zip(l, x)]
This outputs:
[5, 0, 6, 7, 0, 0, 0, 0, 8, 0]

finding all occurences of a minimum value in a list using for loop

Sorry If this has already been asked but I can't seem to find the answer I'm looking for, they all have involved using tools we aren't allowed to use yet.
The question is I have to use a for loop to go through a list and find the minimum value and then return the index of that value. That part I'm okay with, the issue I'm having is how do I get the program to return all the occurrences of that min value?
Restrictions
I can't use anything like enumerate or other such functions, I'm allowed to use the min function but that's it and it has to be done within a for loop.
Any help would be appreciated, thanks!
n = [1, 2, 3, -50, -60, 0, 6, 9, -60, -60]
for i in n:
min_val = []
item = min(n)
item_index = n.index(item)
min_val.append(item_index)
print(min_val)
I'm assuming this is python so you can use numpy
import numpy as np
n = np.array([1, 2, 3, -50, -60, 0, 6, 9, -60, -60])
searchKey = -60
item_index = np.where(n == searchKey)[0]
item_index => array([4, 8, 9])
if you don't know the minimum value ahead of time you can use a for-loop like this:
minval = n[0]
for i in n:
if i < minval:
minval = i
then just replace searchKey with minval above
disclaimer: n is of type np.array not list, not sure if this matters to you but if so I can post a less eloquent list solution that doesn't use enumerate.
Here is the solution to this:
n = [1, 2, 3, -50, -60, 0, 6, 9, -60, -60]
for i in n:
min_count = n.count(min(n)) # getting a count of the number of minimum values
min_value = min(n)
min_index_list = []
for j in range(min_count):
min_index = n.index(min_value)
min_index_list.append(min_index)
n[min_index] += 1
break
print(min(n) - 1, min_index_list)
The following list Comprehension will do the work in one line
min_val_idxs = [ x for x in range(len(n)) if n[x] == min(n)]
Using a for-loop:
create an empty list, indices
this is done before / outside of the loop, otherwise the list is reset with each iteration.
create the loop with for i in range(len(x)):, which essentially iterates through a list of index locations [0, 1, 2, 3, ..., len(x)-1]
for i in n: just iterates through each value in your list
in the loop, add any i, where x[i] is a match to min(x), to the list
def get_indices(x: list) -> list:
indices = list()
min_val = min(x)
for i in range(len(x)):
if x[i] == min_val:
indices.append(i)
return indices
print(get_indices(n))
>>> [4, 8, 9]

Get randomly the 3 minimum values of an repeated-values array in Python

I've an array my_array and I want, due to specific reasons ignore the values -5 and -10 of it (yes, in the example below there's not a -10 but in other arrays I've to manage yes), and get the index of the three minimum values of the array, and append them to a new list titled lista_indices_candidatos.
This is my code.
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
a = np.array(my_array)
indices = a.argsort()
indices = indices[a[indices] != -5]
indices = indices[a[indices] != -10]
lista_indices_candidatos = []
for i in indices[:3]:
lista_indices_candidatos.append(i)
print lista_indices_candidatos
This gets me the index of the 3 minimum values [6, 0, 3] from the array [4, -5, 10, 4, 4, 4, 0, 4, 4]
The thing is that, if there are repeated values, this get's me the first three minimum values (the first 4 (index 0) the second 4 (index 3), ignoring the rest 4's of the array.
How can I change the code to get completely randomly the three minimum values, without taking always the first three?
myArray = [4, -5, 10, 4, 4, 4, 0, 4, 4]
myUniqueArray = list(set(myArray))
myUniqueArray.sort()
return [myArray.index(myUniqueArray[0]), myArray.index(myUniqueArray[1]), myArray.index(myUniqueArray[2])]
.index would not give you a random index in the sense that it will always be the same value for a give set of input list but you could play with that part.
I haven't introduced randomness, because it don't really see the point for doing this.
If you need the first 3 lowest positive values:
sorted([x for x in my_array if x >= 0])[:3]
If you need the first three lowest positive values and their initial index:
sorted([(x,idx) for idx,x in enumerate(my_array) if x >= 0], key=lambda t: t[0])[:3]
If you just need the first 3 lowest positive values initial indexes:
[i for x,i in sorted([(x,idx) for idx,x in enumerate(my_array) if x >= 0], key=lambda t: t[0])[:3]]
My take is that you want to get 3 random indices for values in my_array, excluding [-10, -5], the 3 random indices must be chosen within the index list of the 3 lowest values of the remaining set, right?
What about this:
from random import sample
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
sample([i for i, x in enumerate(my_array) if x in sorted(set(my_array) - {-10, -5})[:3]], 3)
Factoring out the limited set of values, that would be:
from random import sample
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
filtered_list = sorted(set(my_array) - {-10, -5})[:3]
# Print 3 sample indices from my_array
print sample([i for i, x in enumerate(my_array) if x in filtered_list], 3)
Ok, I'm also not sure what you are trying to achieve. I like the simplicity of Nasha's answer, but I think you want to always have the index of the 0 in the result set. The way I understand you, you want the index of the lowest three values and only if one of those values is listed more than once, do you want to pick randomly from those.
Here's my try a solution:
import random
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
my_dict = {}
lista_indices_candidatos = []
for index, item in enumerate(my_array):
try:
my_dict[item] = my_dict[item] + [index]
except:
my_dict[item] = [index]
for i in [x for x in sorted(my_array) if x != -10 and x != -5][:3]:
lista_indices_candidatos.append(random.choice(my_dict[i]))
print lista_indices_candidatos
In this solution, I build a dictionary with all the values from my_array as keys. The values of the dictionary is a list of indexes these numbers have in my_array. I then use a list comprehension and slicing to get the three lowest values to iterate over in the for loop. There, I can randomly pick an index for a given value by randomly selecting from my_dict.
I bet there are better ways to achieve what you want to achieve, though. Maybe you can let us know what it is you are trying to do so we can improve on our answers.
After reading your comment, I see that you do not actually want a completely random selection, but instead a random selection without repetition. So here's an updated version.
import random
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
my_dict = {}
lista_indices_candidatos = []
for index, item in enumerate(my_array):
try:
my_dict[item] = my_dict[item] + [index]
except:
my_dict[item] = [index]
for l in my_dict:
random.shuffle(my_dict[l])
for i in [x for x in sorted(my_array) if x != -10 and x != -5][:3]:
lista_indices_candidatos.append(my_dict[i].pop())
print lista_indices_candidatos
How about this one:
import random
def eachIndexSorted(a): # ... without -5 and -10
for value in sorted(set(a) - { -5, -10 }):
indexes = [ i for i in range(len(a)) if a[i] == value ]
random.shuffle(indexes)
for i in indexes:
yield i
def firstN(iterator, n):
for i in range(n):
yield iterator.next()
print list(firstN(eachIndexSorted(my_array), 3))
If you have very large data, then sorting the complete set might be too costly; finding each next minimum iteratively might then be a better approach. (Ask for more details if this aspect is unclear and important for you.)

How to turn all numbers in a list into their negative counterparts? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Apply function to each element of a list
(4 answers)
Closed 7 months ago.
I am trying to turn a list of positive numbers into a list of negative numbers with the same value in python 3.3.3
For example turning [1,2,3] into [-1,-2,-3]
I have this code:
xamount=int(input("How much of x is there"))
integeramount=int(input("How much of the integer is there"))
a=1
lista=[]
while(a<=integeramount):
if(integeramount%a==0):
lista.extend([a])
a=a+1
listb=lista
print(listb)
[ -x for x in listb]
print(listb)
This prints two identical lists when I want one to be positive and one to be negative.
The most natural way is to use a list comprehension:
mylist = [ 1, 2, 3, -7]
myneglist = [ -x for x in mylist]
print(myneglist)
Gives
[-1, -2, -3, 7]
If you want to modify a list in place:
mylist = [ 1, 2, 3, -7]
print(mylist)
for i in range(len(mylist)):
mylist[i] = -mylist[i]
print(mylist)
You can use the numpy package and do numpy.negative()
For large list, consider using numpy
import numpy as np
a=np.array([1,2,3,4])
# result as a numpy array
b=-a
# can be casted back to list
c=list(b)
There is also this method:
Little note, this will only work if all numbers start positive. It won't affect 0. If you have negative numbers you don't want changing you need to add the IF statement below.
if num < 0: continue
numbers = [1, 2, 3, 4 ,5]
for num in numbers:
numbers[num-1] = num - (2*num)
numbers
[-1, -2, -3, -4, -5]
I was going to offer another solution using map:
>>> from operator import neg
>>> list(map(neg, data))
Although I wanted to see the speed vs just the simple comprehension as well as vs numpy, and while it depends on the length of the list for the native solutions, numpy is the way to go for large datasets:
Code for replicating plot:
import perfplot
import numpy as np
from operator import neg
def list_comp(data): return [ -x for x in data]
def map_neg(data): return list(map(neg, data))
def np_neg(data): return np.negative(data)
perfplot.save(
"argsort.png",
setup=lambda n: np.random.rand(n),
kernels=[list_comp, map_neg, np_neg],
n_range=[2 ** k for k in range(15)],
xlabel="len(data)",
)
Use map and lambda to do this, just like a Python pro ;)
mylist = [-2, -1, 0, 1, 2]
mylist = list(map(lambda x: -x if x > 0 else x, mylist)) # Or "lambda x: x*-1"
print(mylist) # [-2, -1, 0, -1, -2]

Unexpected result after using generator expression

I am trying to filter some data I am working with to take out some artifacts such as negative numbers and errors in my measuring devices. I have been playing with the idea of using a generator to do this. I am using Python 2.7.2
testlist = [12,2,1,1,1,0,-3,-3,-1]
gen = (i for i, x in enumerate(testlist) if x < 0 or x > 2.5)
for i in gen: testlist.pop(i)
print testlist
This returns:
[2, 1, 1, 1, 0, -3]
My question is why is the -3 value showing up in the updated "testlist"?
When you remove items from your list, the indexes of the items after it change (they are all shifted down by one). As a result, the generator will skip over some items. Try adding some more print statements so that you can see what is going on:
for i in gen:
print i
print testlist
testlist.pop(i)
Output:
0
[12, 2, 1, 1, 1, 0, -3, -3, -1]
5
[2, 1, 1, 1, 0, -3, -3, -1]
6
[2, 1, 1, 1, 0, -3, -1]
You would have needed to delete items at index 0, 5, 5, 5. The generator produces the indexes 0, 5, 6. That makes sense because enumerate returns 0, 1, 2, ... etc. It won't return the same index twice in a row.
It's also very inefficient to remove the elements one at a time. This requires moving data around multiple times, with a worst case performance of O(n2). You can instead use a list comprehension.
testlist = [x for x in testlist if 0 <= x <= 2.5]
The better way to do this is to use a list comprehension to create a new filtered list:
testlist = [12,2,1,1,1,0,-3,-3,-1]
testlist[:] = [x for x in testlist if 0 <= x <= 2.5]
giving:
[2, 1, 1, 1, 0]
Let's consider a simpler input:
[-3, -4, -5]
First (0, -3) is taken from the enumerator. 0 is added to the generator. The for loop notices that a new element is available from the generator and removes -3:
[-4, -5]
Take a new element from the enumerator. The enumerator remembers taking the first element, so it will now take the second: -5. -5 is removed from the list in the same way. -4 remains.
By the way, an easier way to do what you're trying is the following:
testlist = filter(lambda x: x >= 0 and x <= 2.5, testlist)
You are modifying the list you are working on, somewhat analogous to modifying the index value of, for instance, a for-loop from inside the loop, in some other languages. Consider this approach as an alternative:
testlist = [x for x in testlist if x >= 0 and x <= 2.5]
using list comprehension should work more directly, though it's not a generator expression, but could trivially changed to one:
testlist = (x for x in testlist if x >= 0 and x <= 2.5)

Categories

Resources