There are multiple ways to loop back in python
For example we have
arr=[5,6,8]
for i in range(len(arr)-1, -1, -1):
print(i," ",arr[i])
which gives
2 8
1 6
0 5
I can solve what I need with that, but I am curious. There is another way to loop back which is
for im in arr[::-1]:
print(im)
Looks nice, right?
This gives
8
6
5
My question is, using this second method is there a way to get not only the element but also the index? (the 2,1,0)
There's a builtin for that: reversed. This might be more readable and intuitive than using a range or slice with negative step.
For just the index, you can pass the range to reversed directly:
arr = list("ABC")
for i in reversed(range(len(arr))):
print(i, arr[i])
# 2 C
# 1 B
# 0 A
For index and element, you have to collect the enumerate iterator into a list before reversing:
for i, x in reversed(list(enumerate(arr))):
print(i, x)
# 2 C
# 1 B
# 0 A
use the builtin method reversed
arr = [5, 6, 8]
for i in reversed(range(0,len(arr))):
print(i,arr[i])
Here's a way using reversed() and zip() that should be memory efficient:
arr = [5, 6, 8]
for idx, elem in zip(reversed(range(len(arr))),
reversed(arr)
):
print(idx, elem)
Output:
2 8
1 6
0 5
for idx, elem in list(enumerate(arr))[::-1]:
print(idx, elem)
This uses enumerate to keep elements with their specific index. Then we convert it to list and reverse (enumerate result is not reversible without converting). No need to keep track of any order (like subtracting) manually
You can also just reverse the forward range:
for idx in range(len(arr))[::-1]:
print(idx, arr[idx])
Python actually reverses range in a smart way, without converting it to a list, so it works even for big stuff:
>>> range(10)[::-1]
range(9, -1, -1)
This means that range(len(arr))[::-1] will work in exactly the same way, with exactly the same speed, as your range(len(arr)-1, -1, -1) while looking nice!
i = len(arr) - 1
for im in arr[::-1]:
print(i, " ", im)
i -= 1
You can use enumerate and subtract from the initial length:
arr=[5,6,8]
for i,im in enumerate(arr[::-1]):
print(len(arr)-i-1, im)
output:
2 8
1 6
0 5
The normal way to iterate with an index is with enumerate. One can use this to index the other way by subtracting the index from the length of the sequence:
In [51]: arr = [5, 6, 8]
...: for i, n in enumerate(arr):
...: print(i, n)
...:
0 5
1 6
2 8
In [52]: for i, n in enumerate(reversed(arr)):
...: print(len(arr) - i - 1, n)
...:
2 8
1 6
0 5
Note that reversed doesn't create a new list in memory and is preferable to [::-1] if just iterating.
Related
I have two columns, A and B. I also have a list of tuples. I want to remove any rows where it matches any of the tuples in the list. For example:
Input:
A
B
A
1
A
4
B
2
A
3
[(A,1),(C,4),(A,3)]
Output:
A
B
A
4
B
2
You can use zip + list comprehension:
tuples = [('A', 1), ('C', 4), ('A', 3)]
new_df = df[[x not in tuples for x in zip(df['A'], df['B'])]]
Output:
>>> new_df
A B
1 A 4
2 B 2
Use zip + pandas series to do without for loop (should be faster)
Note: Based upon How to filter a pandas DataFrame according to a list of tuples
tuples = [('A',1),('C',4),('A',3)]
new_df = df[~pd.Series(list(zip(df['A'], df['B']))).isin(tuples)] # no for loop
>>> new_df
A B
1 A 4
2 B 2
I think the best you can do here is to throw all the "blacklisted" tuples into a set (i.e. hash them) and perform a membership test on each row in your list. The membership test will take constant time & the overall time complexity of this algorithm will be O(n + m), with n being the number of items in your list and m being the number of items in your blacklist.
def solve(arr, blacklist):
S = set(blacklist)
result = [None] * len(arr)
idx = 0
for i in range(len(arr)):
if arr[i] not in S:
result[idx] = arr[i]
idx += 1
return result[:idx]
A "pure" pandas solution (whatever that means):
df[~df.set_index(['A','B']).index.isin(tuples)]
output
A B
1 A 4
2 B 2
I was storing a list with elements
[0, 1, 2, 3, 4, 4]
When I iterated through it and printed each element's index, my output was something like this:
0
1
2
3
4
4
I just thought if it was printing just the elements so I tried one more input
[1,2,3,4,5,6,7]
and this time I got proper indexes like
0
1
2
3
4
5
6
Why happened in the first case and how can I solve this?
n=input()
l=list(input().split())
print(l)
for i in l:
print(l.index(i))
Expected Output:
0
1
2
3
4
5
Actual Output:
0
1
2
3
4
4
The .index function doesn't work as you expected.
.index() doesn't return the index of the item in the array, it returns you the first index or location of the value (see this).
In your code
l = [0, 1, 2, 3, 4, 4]
for i in l:
print(l.index(i)) #i is the value itself
What's actually happening is that each time it's searching for the first occurrence of the value i. In the list l = [0, 1, 2, 3, 4, 4], when you reach the last 4, you actually ask Python to give you the "first occurrence of 4 in the list l", so Python gives you the "index" 4.
In JavaScript, it'll be the equivalent of array.indexOf(val).
What you seem to be looking for is the enumerate function:
for ind, val in enumerate(l):
...
Use enumerate() if you would like to get the position of the elements in the list.
Or, if you just want to print the values:
for i in l:
print(i)
Documentation:
https://docs.python.org/3/tutorial/datastructures.html?highlight=list%20index
list.index(x[, start[, end]])
Return zero-based index in the list of the first item whose value
is equal to x. Raises a ValueError if there is no such item.
https://docs.python.org/3/library/functions.html#enumerate
enumerate(iterable, start=0)
Return an enumerate object. iterable must be a sequence, an iterator,
or some other object which supports iteration. The next() method
of the iterator returned by enumerate() returns a tuple containing a
count (from start which defaults to 0) and the values obtained from
iterating over iterable.
list_name.index(i) returns the index of the first occurrence that element.
So, if your list was:
[1,2,3,4,5,6,5]
And you printed out l.index(i) by iterating over the list, the output would be.
0
1
2
3
4
5
4
Because 5 has the first occurrence at position 4 in the list.
I am trying to print the row number and column number of a matrix where the value is 1.
For example:
A=[0 1 0]
[1 0 1]
[1 0 0]
I want the output to be displayed as:(row number followed by the corresponding column)
0 1
1 0 2
2 0
I tried to use enumerate() but it gave me different kind of output.
G={i: [j for j, y in enumerate(row) if y] for i, row in enumerate(A)}
print (G)
Python's indices are zero-based. You have done everything correctly, but just need to add a couple of +1s to get the output you expected. Also, dictionaries are unordered by nature, so you would be better off just using a list of tuples:
G = [(i+1, [j+1 for j, y in enumerate(row) if y]) for i, row in enumerate(A)]
Or better still; just a 2d list using the indices as the first column when you need them.
This question already has answers here:
remove zero lines 2-D numpy array
(4 answers)
Closed 6 years ago.
I'm trying to write a function to delete all rows in which have a zero value in.
This is not from my code, but an example of the idea I am using:
import numpy as np
a=np.array(([7,1,2,8],[4,0,3,2],[5,8,3,6],[4,3,2,0]))
b=[]
for i in range(len(a)):
for j in range (len(a[i])):
if a[i][j]==0:
b.append(i)
print 'b=', b
for zero_row in b:
x=np.delete(a,zero_row, 0)
print 'a=',a
and this is my output:
b= [1, 3]
a= [[7 1 2 8]
[4 0 3 2]
[5 8 3 6]
[4 3 2 0]]
How do I get rid of the rows with the index in b?
Sorry, I'm fairly new to this any help would be really appreciated.
I'm trying to write a function to delete all rows in which have a zero value in.
You don't need to write a function for that, it can be done in a single expression:
>>> a[np.all(a != 0, axis=1)]
array([[7, 1, 2, 8],
[5, 8, 3, 6]])
Read as: select from a all rows that are entirely non-zero.
Looks like np.delete does't change the array, just returns a new array, so
Instead of
x = np.delete(a,zero_row, 0)
try
a = np.delete(a,zero_row, 0)
I think I have found the answer:
as #tuxcanfly said I changed x to a.
Also I have now removed the for loop as it removed the row with index 2 for some reason.
Instead I now just chose to delete the rows using b as the delete function with use the elements in the list to remove the row with that index.
the new code:
import numpy as np
a=np.array(([7,1,2,8],[4,0,3,2],[5,8,3,6],[4,3,2,0]))
b=[]
for i in range(len(a)):
for j in range (len(a[i])):
if a[i][j]==0:
b.append(i)
print 'b=',b
for zero_row in b:
a=np.delete(a,b, 0)
print 'a=',a
and the output:
b= [1, 3]
a= [[7 1 2 8]
[5 8 3 6]]
I think this helps readability (and allows you to loop once, not twice):
#!/usr/bin/env python
import numpy as np
a = np.array(([7,1,2,8], [4,0,3,2], [5,8,3,6], [4,3,2,0]))
b = None
for row in a:
if 0 not in row:
b = np.vstack((b, row)) if b is not None else row
a = b
print 'a = ', a
In this version, you loop over each row and test for 0's membership in the row. If the row does not contain a zero, you attempt to use np.vstack to append the row to an array called b. If b has not yet been assigned to, it is initialized to the current row.
list.index() will give you the index of the first time the value is shown in the list, but I am looking for a way that will return the index of that specific item, regardless of whether it is repeated, for example, if were to use it like so:
lst = [1,4,5,1,4]
for i in lst:
lst.something(i)
would return
0
1
2
3
4
Any help appreciated
Are you looking for enumerate?
>>> lst = [1,4,5,1,4]
>>> for index, elm in enumerate(lst):
... print index, elm
...
0 1
1 4
2 5
3 1
4 4
>>>
use enumerate
for i,_ in enumerate(listt):
print i
No, it's not possible for lst.something(1) to know whether to return 0 or 3 depending on which 1 it was called with. int is a primitive type, so any 1 is just the same as another 1.
As proof, you can use the is operator:
lst = [1, 4, 5, 1, 4]
print lst[0] is lst[3]
# True
So when the hypothetical function lst.something(1) is called, it won't know which 1 you meant, regardless of how you called it.