I'm working through this thing on pyschools and it has me mystified.
Here's the code:
def convertVector(numbers):
totes = []
for i in numbers:
if i!= 0:
totes.append((numbers.index(i),i))
return dict((totes))
Its supposed to take a 'sparse vector' as input (ex: [1, 0, 1 , 0, 2, 0, 1, 0, 0, 1, 0])
and return a dict mapping non-zero entries to their index.
so a dict with 0:1, 2:1, etc where x is the non zero item in the list and y is its index.
So for the example number it wants this: {0: 1, 9: 1, 2: 1, 4: 2, 6: 1}
but instead gives me this: {0: 1, 4: 2} (before its turned to a dict it looks like this:
[(0, 1), (0, 1), (4, 2), (0, 1), (0, 1)]
My plan is for i to iterate through numbers, create a tuple of that number and its index, and then turn that into a dict. The code seems straightforward, I'm at a loss.
It just looks to me like numbers.index(i) is not returning the index, but instead returning some other, unsuspected number.
Is my understanding of index() defective? Are there known index issues?
Any ideas?
index() only returns the first:
>>> a = [1,2,3,3]
>>> help(a.index)
Help on built-in function index:
index(...)
L.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.
If you want both the number and the index, you can take advantage of enumerate:
>>> for i, n in enumerate([10,5,30]):
... print i,n
...
0 10
1 5
2 30
and modify your code appropriately:
def convertVector(numbers):
totes = []
for i, number in enumerate(numbers):
if number != 0:
totes.append((i, number))
return dict((totes))
which produces
>>> convertVector([1, 0, 1 , 0, 2, 0, 1, 0, 0, 1, 0])
{0: 1, 9: 1, 2: 1, 4: 2, 6: 1}
[Although, as someone pointed out though I can't find it now, it'd be easier to write totes = {} and assign to it directly using totes[i] = number than go via a list.]
What you're trying to do, it could be done in one line:
>>> dict((index,num) for index,num in enumerate(numbers) if num != 0)
{0: 1, 2: 1, 4: 2, 6: 1, 9: 1}
Yes your understanding of list.index is incorrect. It finds the position of the first item in the list which compares equal with the argument.
To get the index of the current item, you want to iterate over with enumerate:
for index, item in enumerate(iterable):
# blah blah
The problem is that .index() looks for the first occurence of a certain argument. So for your example it always returns 0 if you run it with argument 1.
You could make use of the built in enumerate function like this:
for index, value in enumerate(numbers):
if value != 0:
totes.append((index, value))
Check the documentation for index:
Return the index in the list of the first item whose value is x. It is
an error if there is no such item.
According to this definition, the following code appends, for each value in numbers a tuple made of the value and the first position of this value in the whole list.
totes = []
for i in numbers:
if i!= 0:
totes.append((numbers.index(i),i))
The result in the totes list is correct: [(0, 1), (0, 1), (4, 2), (0, 1), (0, 1)].
When turning it into again, again, the result is correct, since for each possible value, you get the position of its first occurrence in the original list.
You would get the result you want using i as the index instead:
result = {}
for i in range(len(numbers)):
if numbers[i] != 0:
result[i] = numbers[i]
index() returns the index of the first occurrence of the item in the list. Your list has duplicates which is the cause of your confusion. So index(1) will always return 0. You can't expect it to know which of the many instances of 1 you are looking for.
I would write it like this:
totes = {}
for i, num in enumerate(numbers):
if num != 0:
totes[i] = num
and avoid the intermediate list altogether.
Riffing on #DSM:
def convertVector(numbers):
return dict((i, number) for i, number in enumerate(numbers) if number)
Or, on re-reading, as #Rik Poggi actually suggests.
Related
so I followed a tutorial to learn how to complete 2 sum and I understand what ever line means but I dont understand why diffs[list[i]] returns the 0 index. I went through the the algorithm with the current arguments and i comes out to 3 when it returns the indexes
diffs = {} # Make a hash map to store values
for i in range(len(list)): # Iterate through list
if list[i] in diffs: # If the number you are on is in the has map
return [diffs[list[i]], i] # return indexes
else:
diffs[target - list[i]] = i
print(twosum([2, 11, 15, 7], 9))
def twosum(nums, target):
diffs = {} # Make a hash map to store values
for i in range(len(nums)): # Iterate through list
if nums[i] in diffs: # If the number you are on is in the has map
return [diffs[nums[i]], i] # return indexes
else:
diffs[target - nums[i]] = i
print(i, diffs)
In [4]: print(twosum([2, 11, 15, 7], 9))
0 {7: 0}
1 {7: 0, -2: 1}
2 {7: 0, -2: 1, -6: 2}
[0, 3]
As you can see from the above output, 7 has index 0 in the dictionary. It's the first element that is added to the dictionary. The reason is that you are saving the differences in the dictionary. target - nums[0] is 7 in this case because nums[0] is 2.
Then, when you reach the last element, namely 7, you find it in the dictionary with the index 0. That is diffs[nums[3]] == diffs[7] == 0. And you return [diffs[nums[i]], i] == [diffs[nums[3]], 3] == [diffs[7], 3] == [0, 3].
Also, don't use the name list to name your variables.
On the first run of the loop. diffs[target - list[i]] = i sets diffs to {7: 0}. That's how diffs[list[3]] evaluates to 0. Eg.
diffs[list[3]]
diffs[7]
0
This question already has answers here:
Problem removing leading zeros using a list comprehension best expression
(2 answers)
Closed 3 years ago.
Trying to remove all the leading zeroes from a list of array using next() and enumerate within a list comprehension. Came across the below code which works. Can anyone explain clearly what the code does.
example : result = [0,0,1,2,0,0,3] returns result = [1,2,0,0,3]
Edited* - the code just removes the leading zeroes
result = result[next((i for i, x in enumerate(result) if x != 0), len(result)):]
print(result)
Trying to remove all the leading zeroes from a list of array using
next() and enumerate within a list comprehension.
Are you obligated to use next(), enumerate() and a list comprehension? An alternate approach:
from itertools import dropwhile
from operator import not_ as is_zero
result = dropwhile(is_zero, [0, 0, 1, 2, 0, 0, 3])
print(*result)
OUTPUT
% python3 test.py
1 2 0 0 3
%
We can potentially explain the original code:
result = [0, 0, 1, 2, 0, 0, 3]
result[next((i for i, x in enumerate(result) if x != 0), len(result)):]
By breaking it down into pieces and executing them:
enumerate(result) # list of indexes and values [(i0, x0), (i1, x1), ...]
[(0, 0), (1, 0), (2, 1), (3, 2), (4, 0), (5, 0), (6, 3)]
[i for i, x in enumerate(result)] # just the indexes
[i for i, x in [(0, 0), (1, 0), ..., (5, 0), (6, 3)]] # what effectively happens
[0, 1, 2, 3, 4, 5, 6]
[i for i, x in enumerate(result) if x != 0] # just the indexes of non-zero values
[2, 3, 6]
# not needed with this example input, used to make an all
# zero list like [0, 0, ..., 0] return the empty list []
len(result)
7
# pull off the first element of list of indexes of non-zero values
next((i for i, x in enumerate(result) if x != 0), len(result))
next(iter([2, 3, 6]), 7) # what effectively happens
2
result[next((i for i, x in enumerate(result) if x != 0), len(result)):] # slice
result[2:] # what effectively happens
[1, 2, 0, 0, 3]
So lets unpack the code from inside out.
(i for i, x in enumerate(result) if x != 0) is a generator for all indices of values that are not zero.
next((i for i, x in enumerate(result) if x != 0), len(result)) returns the first value of the generator (so the index of the first value that is not zero). len(result) is the default value, if the generator does not return any value. So we could also extract this result into a new variable.
index = next((i for i, x in enumerate(result) if x != 0), len(result))
result = result[index:]
The last step is a simple list comprehension and only takes values from the list with an index equals or higher than the given one.
I have a dictionary L, whose keys are tuple of length 2: the first element is an index, the second element is either 0 or 1. I'm defining several functions. In one of them, I need to consider the second element of the tuple, therefore I need it to stay there.
But now I have trouble in another function, in which I do not care at all about it. I have to retrieve the dict value of a given index (first element of the tuple), but I have no idea if the second value is a 0 or a 1.
Is there a mute variable, or something that I can pass and it says "either 0 or 1"?
To make things clearer, I would like to have something like:
needed_value = L.get((given_index, either))
where "either" could be 0 or 1.
For now, I created an if/else, but it seems stupid, because both their body just assign the value.
Thank you very much,
I hope I didn't miss a preexisting solution for this problem!
Edit:
My dict is something like:
L = {(7, 1): 0, (2, 0): 1, (5, 1): 4, (1, 1): 2, (11, 0): 3}
So, I know for sure that the second value in the keys is 0 or (exclusive) 1. Moreover, the first value is unique (if it is relevant).
The code with if/else was (more or less, I do not have it anymore):
if (i, 1) in L.keys():
tau = L.get((i, 1))
elif (i, 0) in L.keys():
tau = L.get((i, 0))
No, there's no way to do this. If you need to retrieve elements by the first part only, then you should make that the key and store the other part in the value.
No. Dictionary keys are hashed and you can't query them database-style with partial tuple matches.
What you can do, if you are sure that either 0 or 1 exists (but, for clarity and in Python <3.6, not both), is to use the optional fallback argument of dict.get:
L = {(10, 1): 5, (10, 2): 6, (10, 3): 7}
val = L.get((10, 0), L.get((10, 1)))
print(val) # 5
Alternatively, and to account for the case when both (10, 0) and (10, 1) exist, you can use a custom function:
L = {(10, 1): 5, (10, 2): 6, (10, 3): 7, (10, 0): 8}
def get_val(x, key):
try:
return x[(key, 0)]
except KeyError:
return x[(key, 1)]
val = get_val(L, 10)
print(val) # 8
Assuming you have something like this:
L = {(10, 1): 5, (10, 0): 6, (20, 0): 7}
And you want to get all the values that correspond to keys starting with, e.g., 10, aka (10, 0) and (10, 1)
to_match = 10
You can do:
res = [v for k, v in L.items() if any(k == (to_match, x) for x in (0, 1))]
which returns:
[5, 6]
As everyone already mentionned, you can't do this out of the box. Now if you need both ways to get the value(s) - one from the full key and another from a "partial" key, a solution might be to maintain a key[0]=>[keys...] mapping in parallel, ie:
L = {(10, 1): 5, (10, 0): 6, (20, 0): 7}
index = defaultdict(list)
for key in L:
index[key[0]].append(key)
Then you can get the list of "complete" keys for a partial one
keys = index.get(10)
values = [L[k] for k in keys]
Of course this means you have to make sure you keep your index up to date so you would need to wrap this all in a class to make sure all updates to L are reflected in index.
list = [('a5', 1), 1, ('a1', 1), 0, 0]
I want to group the elements of the list into 3, if the second or third element is missing in the list 'None' has to appended in the corresponding location.
exepected_output = [[('a5', 1), 1,None],[('a1', 1), 0, 0]]
Is there a pythonic way for this? New to this, any suggestions would be helpful.
Here's a slightly different approach from the other answers, doing a comparison on the type of each element and then breaking the original list into chunks.
li = [('a5', 1), 1, ('a1', 1), 0, 0]
for i in range(0, len(li), 3):
if type(li[i]) is not tuple:
li.insert(i, None)
if type(li[i+1]) is not int:
li.insert(i+1, None)
if type(li[i+2]) is not int:
li.insert(i+2, None)
print [li[i:i + 3] for i in range(0, len(li), 3)]
As far as I am aware, the only way to get the result you want is to loop through your list and detect when you encounter tuples.
Example which should work:
temp = None
result = []
for item in this_list:
if type(item) == tuple:
if temp is not None:
while len(temp) < 3:
temp.append(None)
result.append(temp)
temp = []
temp.append(item)
Edit: As someone correctly commented, don't name a variable list, you'd be overwriting the built in list function. Changed name in example.
I have a list of tuples: a = [(1,2),(1,4),(1,2),(6,7),(2,9)] I want to check if one of the individual elements of each tuple matches the same position/element in another tuple, and how many times this occurs.
For example: If only the 1st element in some tuples has a duplicate, return the tuple and how many times it's duplicated.
I can do that with the following code:
a = [(1,2), (1,4), (1,2), (6,7), (2,9)]
coll_list = []
for t in a:
coll_cnt = 0
for b in a:
if b[0] == t[0]:
coll_cnt = coll_cnt + 1
print "%s,%d" %(t,coll_cnt)
coll_list.append((t,coll_cnt))
print coll_list
I want to know if there is a more effective way to do this?
You can use a Counter
from collections import Counter
a = [(1,2),(1,4),(1,2),(6,7),(2,9)]
counter=Counter(a)
print counter
This will output:
Counter({(1, 2): 2, (6, 7): 1, (2, 9): 1, (1, 4): 1})
It is a dictionary like object with the item (tuples in this case) as the key and a value containing the number of times that key was seen. Your (1,2) tuple is seen twice, while all others are only seen once.
>>> counter[(1,2)]
2
If you are interested in each individual portion of the tuple, you can utilize the same logic for each element in the tuple.
first_element = Counter([x for (x,y) in a])
second_element = Counter([y for (x,y) in a])
first_element and second_element now contain a Counter of the number of times values are seen per element in the tuple
>>> first_element
Counter({1: 3, 2: 1, 6: 1})
>>> second_element
Counter({2: 2, 9: 1, 4: 1, 7: 1})
Again, these are dictionary like objects, so you can check how frequent a specific value appeared directly:
>>> first_element[2]
1
In the first element of your list of tuples, the value 2 appeared 1 time.
use collections library. In the following code val_1, val_2 give you duplicates of each first elements and second elements of the tuples respectively.
import collections
val_1=collections.Counter([x for (x,y) in a])
val_2=collections.Counter([y for (x,y) in a])
>>> print val_1
<<< Counter({1: 3, 2: 1, 6: 1})
This is the number of occurrences of the first element of each tuple
>>> print val_2
<<< Counter({2: 2, 9: 1, 4: 1, 7: 1})
This is the number of occurrences of the second element of each tuple
You can make count_map, and store the count of each tuple as the value.
>>> count_map = {}
>>> for t in a:
... count_map[t] = count_map.get(t, 0) +1
...
>>> count_map
{(1, 2): 2, (6, 7): 1, (2, 9): 1, (1, 4): 1}
Using pandas this is simple and very fast:
import pandas
print(pandas.Series(data=[(1,2),(1,4),(1,2),(6,7),(2,9)]).value_counts())
(1, 2) 2
(1, 4) 1
(6, 7) 1
(2, 9) 1
dtype: int64
Maybe Dictionary can work better. Because in your code, you are traveling the list for twice. And this makes the complexity of your code O(n^2). And this is not a good thing :)
Best way is the travelling for once and to use 1 or 2 conditions for each traverse. Here is the my first solution for such kind of problem.
a = [(1,2),(1,4),(1,2),(6,7),(2,9)]
dict = {}
for (i,j) in a:
if dict.has_key(i):
dict[i] += 1
else:
dict[i] = 1
print dict
For this code, this will give the output:
{1: 3, 2: 1, 6: 1}
I hope it will be helpful.