An example:
example = [None, b'1', b'2', b'3', b'4', b'1', None, None, b'8', b'56', b'66', b'77', b'1', None]
I need to change values in this list in the following way: bytes should be converted to int, None to 0 and every 6th and 7th element to a bool. The expected output:
expected_output = [0, 1, 2, 3, 4, True, False, 0, 8, 56, 66, 77, True, False]
My attempt:
[int(value) if value else bool(value) if index in (5,6) else 0 for index, value in enumerate(example)]
The result:
[0, 1, 2, 3, 4, True, False, 0, 8, 56, 66, 77, 0, 0]
I know there is a problem in this part of my code:
[int(value) if value else bool(value) if index in (5,6) else 0 for index, value in enumerate(example)]
^
|
|
How can I change every 6th and 7th element to a bool?
You need to check whether the index modulo 7 (the number of elements in each group) is 5 or 6. But you also need to do that first since b'1' also passes the if value test:
[bool(value) if index % 7 in (5,6) else int(value) if value else 0 for index, value in enumerate(example)]
Output:
[0, 1, 2, 3, 4, True, False, 0, 8, 56, 66, 77, True, False]
The more logic you add to this list comprehension the more unreadable it will become. I'd suggest you to go with a normal if/elif statement here:
for ix, i in enumerate(example):
if ix % 7 in (5,6):
example[ix] = bool(i)
elif not i:
example[ix] = 0
elif isinstance(i, bytes):
example[ix] = int(i)
print(example)
# [0, 1, 2, 3, 4, True, False, 0, 8, 56, 66, 77, True, False]
Basic
You can implement rotation with %(modulo) operator.
example = [
None, b'1', b'2', b'3', b'4', b'1', None,
None, b'8', b'56', b'66', b'77', b'1', None,
]
results = [
bool(value) if index % 7 in {5, 6} else
int(value) if value else 0
for index, value in enumerate(example)
]
print(results)
output:
[0, 1, 2, 3, 4, True, False, 0, 8, 56, 66, 77, True, False]
Pythonic
But, there is some more pythonic way:
import itertools
example = [
None, b'1', b'2', b'3', b'4', b'1', None,
None, b'8', b'56', b'66', b'77', b'1', None,
]
converters = itertools.cycle(itertools.chain(
itertools.repeat(lambda x: int(x) if x else 0, 5),
itertools.repeat(bool, 2),
))
results = [
converter(value) for converter, value in zip(converters, example)
]
print(results)
output: same with above.
Explanation
itertools.cycle: Make a cyclic iterator.
itertools.chain: Concatenate iterables.
itertools.repeat: Make iterator with repeating by specified number.
So converters = ... part means: lambda x: int(x) if x else 0 fucntion with five times, bool with two times, and repeat this cycle!
You can add multiple rules for each position without complicated if-else.
Related
Given the following list:
x =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
The question asks us to replace None values with the previous value.
When I run both these solutions in Google Colab, they result in the identical answer:
x =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
def replace(x):
for i,v in enumerate(x):
if x[i] is None:
x[i]=x[i-1]
return x
y =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
def replace(y):
for i,v in enumerate(y[:-1],1):
if y[i] is None:
y[i]=y[i-1]
return y
Both return the following:
[None, None, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]
I'm trying to understand why these solutions are equivalent. Additionally, given the equivalence, what is the rationale for the y[:-1] in the enumerate statement?
Thank you.
They are not completely equivalent. The first solution will use the last item in the list to replace the None value at index 0. The second solution does not replace the item at index zero (given that it has no predecessor). So, depending on the wording of the problem statement, one of the solutions is probably wrong.
enumerate has two parameters, an iterable and a start.
When you write enumerate( y[:-1], 1 ) two things happen:
You are giving a chopped of copy of the y array to the for loop ( you chopped of the last element of the array ), but in your for loop, you actually working on the real y array, which is not chopped of.
If you set your y to y = y[:-1] before the for loop and give that to the enumerate ( enumerate( y, 1 ) ) you will see a list is out of index error.
When you give the enumerate a 1 as a starting number, you are actually skipping the first element of your real y array (array index starts at 0, and you are starting with a y[1] in your for loop). Because of that ( and because of the 1. point ) you will reach the last element of the real y array.
enumerate accepts an optional argument that allows us to specify the starting index of the counter. So when you do :
enumerate(y[:-1],1)
instead of :
enumerate(y)
you are just shift your index:
0 None
1 None
2 1
3 2
4 None
...
vs
1 None
2 None
3 1
4 2
5 None
...
And to conclude, given that your input is a list, and that you add an index using enumerate, BUT your output is a list without any index, obviously you cannot see any difference.
In python when you have a list x and you do x[:-1] you are creating a new list without the last element. You ask for a rationale but I really cannot see how adding this would help in any way.
The fact that you start the enumerate on 1 in the second example can give you some weird behaviour
If you try the following list:
x = [None, None, 1, 2, None, None, 3, 4, None, 5, None, 6]
You will get the next two results:
[6, 6, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6]
[None, None, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6]
This happens since the enumerate starts on 1 so you ignore y[0] = y[-1]
I came across the following in a piece of code:
X = numpy.array()
X[X < np.finfo(float).eps] = np.finfo(float).eps
I found out the following from the documentation:
class numpy.finfo(dtype):
Machine limits for floating point types.
Parameters:
dtype : float, dtype, or instance
Kind of floating point data-type about which to get information.
I understand that np.finfo(float).eps returns the lowest represent-able float value and that X[X < np.finfo(float).eps] = np.finfo(float).eps makes sure that any value less than np.finfo(float).eps is not contained in the array X, but I'm unable to understand how exactly that happens in the statement of the form X[X < {value}] = {value} and what it means. Any help is appreciated much.
The first time I saw it was as a way to replace NaNs in an array
Basically the conditional X < np.finfo(float).eps creates a boolean mask of Xand then X is iterated over replacing values that have a True associated with them.
So for instance,
x=np.array([-4, -3, -2, -1, 0, 1, 2, 3, 4])
x[x < 0] = 0
Here the mask array would look like,
[True, True, True, True, False, False, False, False, False]
Its a quicker way of doing the following with large arrays,
x=np.array([-4, -3, -2, -1, 0, 1, 2, 3, 4])
for y, idx in enumerate(x):
if y < 0:
x[idx] = 0
This is a fancy way of changing values of an array and changing values if condition is met.
On an easy example:
X = np.random.randint(1, 100, size=5)
print(X) # array([ 1, 17, 92, 9, 11])
X[X < 50] = 50 # Change any value lower than 50 to 50
print(X) # array([50, 50, 92, 50, 50])
Basically this changes array X if you don't make a copy of it and former values are lost forever. Using np.where() would achieve same goal, but it would not override the original array.
X = np.random.randint(1, 100, size=5)
print(X) # array([ 1, 17, 92, 9, 11])
np.where(X < 50, 50, X) # array([50, 50, 92, 50, 50])
print(X) # array([ 1, 17, 92, 9, 11])
Extra info:
Fancy indexing You need to scroll a bit down tho (idk how to copy at specific header)
When we index a numpy array X with another array x, the output is a numpy array with values corresponding to the values of X at indices corresponding to the values of x.
And X < {value} returns a numpy array which has boolean values True or False against each item in X depending on whether the item passed the condition {item} < {value}. Hence, X[X < {value}] = {value} means that we're assigning the value {value} whenever an array item is less than {value}. The following would make things more clear:
>>> x = [1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0]
>>> X = numpy.array(x)
>>> X < 1
array([False, False, True, False, False, True, False, False, True,
False, False, True])
>>> X[X < 1] = -1
>>> X
array([ 1, 2, -1, 3, 4, -1, 5, 6, -1, 7, 8, -1])
>>> X[x]
array([ 2, -1, 1, 3, 4, 1, -1, 5, 1, 6, -1, 1])
P.S. : The credit for this answer goes to #ForceBru and his comment above!
So say we have some values:
data = np.random.standard_normal(size = 10)
I want my function to output an array which identifies whether the values in data are positive or not, something like:
[1, 0, 1, 1, 0, 1, 1, 0, 0, 0]
Ive tried
def myfunc():
for a in data > 0:
if a:
return 1
else:
return 0
But I'm only getting the boolean for the first value in the random array data, I don't know how to loop this function to ouput an array.
Thanks
You can do np.where, it's your friend:
np.where(data>0,1,0)
Demo:
print(np.where(data>0,1,0))
Output:
[1 0 1 1 0 1 1 0 0 0]
Do np.where(data>0,1,0).tolist() for getting a list with normal commas, output would be:
[1, 0, 1, 1, 0, 1, 1, 0, 0, 0]
It's very simple with numpy:
posvals = data > 0
>> [True, False, True, True, False, True, True, False, False, False]
If you explicitly want 1s and 0s:
posvals.astype(int)
>> [1, 0, 1, 1, 0, 1, 1, 0, 0, 0]
You can use ternary operators alongside list comprehension.
data = [10, 15, 58, 97, -50, -1, 1, -33]
output = [ 1 if number >= 0 else 0 for number in data ]
print(output)
This would output:
[1, 1, 1, 1, 0, 0, 1, 0]
What's happening is that either '1' or '0' is being assigned with the logic being if the number is bigger (or equal to) 0.
If you'd like this in function form, then it's as simple as:
def pos_or_neg(my_list):
return [ 1 if number >= 0 else 0 for number in data ]
You are attempting to combine an if and a for statement.
Seeing as you want to manipulate each element in the array using the same criteria and then return an updated array, what you want is the map function:
def my_func(data):
def map_func(num):
return num > 0
return map(map_func, data)
The map function will apply map_func() to each number in the data array and replace the current value in the array with the output from map_func()
If you explicitly want 1 and 0, map_func() would be:
def map_func(num):
if num > 0:
return 1
return 0
So im trying to use filter() to find all the prime numbers in a list, but the output is weird. i been stuck on this one for like over an hour...still cant figure out where i did wrong
Here is the code:
TEST_LIST = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
RESULT_LIST = filter(
lambda x: not [x % i == 0 for i in range(2, math.floor(x / 2))], TEST_LIST)
print(TEST_LIST)
print(list(RESULT_LIST))
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5]
First, you may want to fix a bug with your code. You want the range to include x / 2, since otherwise your algorithm breaks for x = 4. A simple way to do this while avoiding using the math module is to use truncating division and just adding one: x // 2 + 1.
Look at the result of your list comprehension:
In [6]: x = 36
In [7]: [x % i == 0 for i in range(2, x // 2 + 1))]
Out[7]:
[True,
True,
True,
False,
True,
False,
False,
True,
False,
False,
True,
False,
False,
False,
False,
False]
Notice that no matter the value of x, the list will always be non-empty. Non-empty lists are truthy, regardless of what they contain:
In [8]: bool([True])
Out[8]: True
In [9]: bool([False])
Out[9]: True
You instead want to check if any value of the list is truthy:
In [10]: any([x % i == 0 for i in range(2, x // 2 + 1)])
Out[10]: True
You can speed this up a little if you don't use a list comprehension and instead use a generator expression, which doesn't produce an intermediate list:
In [11]: any(x % i == 0 for i in range(2, x // 2 + 1))
Out[11]: True
I hope anyone can help me with the following. I have a list called: 'List'. And I have a list called X.
Now I would like to check whether the value in the third column of each row in List is smaller than (<) X or equal/bigger than X. If the value is smaller I would like to add a 0 to the 6th column and a 1 if it is equal/bigger. And for each X I would like the answers to be added to the upfollowing columns to List. So in this case there are 4 X values. So as a result 4 columns should be added to List. My code below probably shows I'm quite an amature and I hope you can help me out. Thank you in advance.
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
for item in X:
for number in row[3] for row in List:
count = 0
if number < item:
List[5+count].append(0)
count += 1
return List
else:
List[5+count].append(1)
count += 1
return List
return List
First, you should know that tuples (parenthesis enclosed lists) are immutable, so you can not change anything about them once they're defined. It's better to use a list in your case (enclosed by []).
List = [[3,5,6,7,6],[3,5,3,2,6],[3,6,1,0,5]]
X= [1,4,5,6]
for item in X: # loop on elements of X
for subList in List: # loop on 'rows' in List
if subList[2] < item: # test if 3rd element is smaller than item in X
subList.append(0); # push 0 to the end of the row
else:
subList.append(1); # push 1 to the end of the row
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
scores = []
for item in List:
scores.append(tuple(map(lambda x: 0 if item[2] < x else 1, X)))
result = []
for item, score in zip(List, scores):
result.append(item + score)
print(result)
# [(3, 5, 6, 7, 6, 1, 1, 1, 1), (3, 5, 3, 2, 6, 1, 0, 0, 0), (3, 6, 1, 0, 5, 1, 0, 0, 0)]
Your indentation is off (you should unindent everything starting with your for statement.
You can't append to tuples (your rows inside the List variable are actually tuples).
Since you are not in a function, return does not do anything.
Since indices start with 0, you should use row[2] for 3rd row.
There are more elements in your X than the number of rows in List.
That being said, you can also use list comprehensions to implement this. Here is a one-liner that does the same thing:
>>> List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
>>> X = [1,4,5,6]
>>> print [tuple(list(t[0])+[0]) if t[0][2] < t[1] else tuple(list(t[0]) + [1]) for t in zip(List, X)]
will print
[(3, 5, 6, 7, 6, 1), (3, 5, 3, 2, 6, 0), (3, 6, 1, 0, 5, 0)]
List = [[3,5,6,7,6],[3,5,3,2,6],[3,6,1,0,5]]
X= [1,4,5,6]
elems = [row[3] for row in List]
for i in range(len(elems)):
for x in X:
if elems[i] < x:
List[i].append(0)
else:
List[i].append(1)
print List
And you cannot use return if you are not using functions.
return needs to be called from inside a function. It exits the function and the value specified by return is given back to the function.
So you can't use it in your program.
In the list, each row is actually known as a tuple. Tuples don't have the append function so you can't use that to add to the end of a row.
Also, you can't have two for loops in a single line. (Which is not a problem since we only need one to achieve your output)
I've modified your code so that it looks similar so it's easier for you to understand.
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
for item in X:
n = 0
for row in list:
if row[3] < item:
list[n] = list[n] + (0,)
else:
list[n] = list[n] + (1,)
n = n+1
print List
You need to add with (0,) or (1,) to show that it's a tuple addition. (Or else python will think that you're adding a tuple with an integer)
agree with Selcuk
[edited #1: Thanks #Rawing, I mistyped > as <]
Here is AlmostGr's version simplified:-
List = [[3, 5, 6, 7, 6], [3, 5, 3, 2, 6], [3, 6, 1, 0, 5]]
X = [1, 4, 5, 6]
for num in X:
for item in List:
if num > item[2]:
item.append(0)
else:
item.append(1)
it runs for all elements in X and produces the output:
[[3, 5, 6, 7, 6, 1, 1, 1, 1], [3, 5, 3, 2, 6, 1, 0, 0, 0], [3, 6, 1, 0, 5, 1, 0, 0, 0]]