Can someone explain the logic behind this code? - python-3.x

a = [1,2,3,4,4,2,2]
d = {k: v for v, k in enumerate(a)}
print(d)
Let me rephrase myself.
from the above code what does this line exactly mean.
{k: v for v, k in enumerate(a)}

First you have enumerate(a). This built-in function adds a counter to an iterable and returns it in a form of enumerating object. So for every element in a, it makes a tuple (index, a[index]), where here: index will increase from 0 to 6.
Then for v, k in enumerate(a): we have already seen what enumerate(a) does, now you tell Python that for each loop, the tuple (index, a[index]) is represented by v, k. So v = index and k = a[index].
Then at last we find {k: v for v, k in enumerate(a)}, the accolades tell that you're making a dictionary. The k: v tells you that every loop, you will take k as a key of your dictionary with v the corresponding value. So the dictionary its keys will exist out of the elements of a, with their corresponding value equaling their indexc in the list a.
Now you have to take in mind that in a dictionary, each key can only exist once. So when the program comes across a key that already exists in the dictionary, it will overwrite it. That is why for example the first '2' with index 1, doesn't show up in the dictionary. Because it gets first overwritten by the '2' with index 5, after which this key and its value get overwritten by the last '2' and its index 6.

#i have added 10 as a last item in your list for easy understanding.
a = [1,2,3,4,4,2,2,10]
d = {k: v for v, k in enumerate(a)} #this is a dictionary comprehension
print(d)
where 'k' returns the items in the list one by one and 'v' returns the count for
each item in list starting from 0.
like k-->v
1-->0
2-->1
3-->2
4-->3
4-->4
2-->5
2-->6
10-->7
The output is {1: 0, 2: 6, 3: 2, 4: 4, 10: 7}
as you know dictionary doesnt allow duplicate keys. when any duplicate key
arrives it rewrites the previous one and holds the latest one.
{1: 0, 2: 6, 3: 2, 4: 4, 10: 7}
as we have 1 in only once in the input list we get 1:0
and for 2 we have three values 1,5,6 as 6 is the latest value. we get
2:6
Like wise happens.

Related

Initialising Python dictionary with list comprehension

I coded up this code randomly trying to learn comprehension and now I am unable to understand what is happening in the code.
lst = "this is really strange behaviour".split()
dt = dict({i,j} for i,j in enumerate(lst))
print(dt)
I tried to make a dictionary with keys as integers and values as corresponding words. But the output of this code is
{0: 'this', 1: 'is', 2: 'really', 'strange': 3, 4: 'behaviour'}
I don't understand why some keys are numbers while others are strings.
P.S. I don't even understand why this syntax is correct and gives no errors.
Please explain about it. Sorry for my bad English.
{i,j} creates a set. Sets have no inherit order, so the set is sometimes i, j and sometimes j, i. dict always use the "first" (left-most) value as the key and the "second" as the value. This means that sometimes i is picked to be the key and sometimes j is.
Use an ordered data-structure instead, for example a tuple:
dt = dict((i, j) for i, j in enumerate(lst))
# ^ ^ note parenthesis to create tuple, not braces
then dt will always be
{0: 'this', 1: 'is', 2: 'really', 3: 'strange', 4: 'behaviour'}
You can actually skip (i, j) for i, j in enumerate(lst) which does nothing useful really, and go straight with
dt = dict(enumerate(lst))
Using a set here does not make any sense. Since elements of a set are unique, this code will break if the list contains a number which happens to equal its index, for example:
lst = ['a', 1]
dt = dict({i, j} for i, j in enumerate(lst))
Will cause an error
ValueError: dictionary update sequence element 1 has length 1; 2 is required
because {1, 1} becomes {1} and dict expects a sequence of key-value pairs.

How to pass an element in list as an index to a list in python?

Given a sorted list [1,2,3,4,5,6,7,8] and a shuffled version of that list
a=[1,2,5,3,7,8,6,4]
I want to find how many steps each element has moved from its position relative to the sorted list (steps towards index 0 being positive, steps away from index 0 being negative) and store those step values in the respective index in a different list.
For the given input, the expected output is:
b=[0,0,-1,-4,2,-1,2,2]
Considering the value 3 (which is at index 2 in the sorted list), in the shuffled array it is at index 3, so it has taken -1 step, and hence b[2] = -1. Similarly for the value 8 (which is at index 7 in the sorted list), in the shuffled array it is at index 5, so it has taken +2 steps, and hence b[7] = 2.
This is what I have tried:
b=[0,0,0,0,0,0,0,0]
a=[1,2,5,3,7,8,6,4]
for x in range(len(a)):
b[a[x]]=a[x]-(x+1)
I am getting an error with this code:
IndexError: list assignment index out of range
Please help me understand this. Why can't I pass an integer from a list as an index to another list?
You can get the result you want with a simple comparison of the expected value at an array position with the index of that value in the a array. By iterating over the number of elements in a, we can generate the output array:
a = [1,2,5,3,7,8,6,4]
b = []
for x in range(len(a)):
b.append(x - a.index(x+1))
print(b)
Output
[0, 0, -1, -4, 2, -1, 2, 2]
Demo on rextester
The problem as you very well know is that there is an index error.
a=[1,2,5,3,7,8,6,4]
The above array has size = 8.
Now you create b:
b=[0,0,0,0,0,0,0,0]
The size of the list b is also 8.
In your for loop you are doing:
b[a[x]]
Pause...
If x is 5, then a[x] will be 8. However, there is no such thing as index 8 in list b, which only has up to index 7.
This is the problem.
You should change the code in your for-loop to:
b[a[x] - 1]=a[x]-(x+1)
I would suggest you change your loop to this:
for x, n in enumerate(a):
b[n-1] = n-(x+1)
Index starts from 0 to n-1
,so in b=[0,0,0,0,0,0,0,0] (having 8 elements) index will start from 0 to 7 and list 'a=[1,2,5,3,7,8,6,4]' contains numbers from 1-8 hence 8 is out of index.
corrected code:
b=[0,0,0,0,0,0,0,0]
a=[1,2,5,3,7,8,6,4]
for x in range(len(a)):
b[a[x] - 1]=a[x]-(x + 1)
Avoiding any indexing, nor unnecessary offsets, we can store the elements in a dictionary (the element as the key and its move as the value)
a=[1,2,5,3,7,8,6,4]
d = {v: v-e for e,v in enumerate(a, 1)}
b = [v for _, v in sorted(d.items())]
print(b)
produces
[0, 0, -1, -4, 2, -1, 2, 2]

How to get list of indices for elements whose value is the maximum in that list

Suppose I have a list l=[3,4,4,2,1,4,6]
I would like to obtain a subset of this list containing the indices of elements whose value is max(l).
In this case, list of indices will be [1,2,5].
I am using this approach to solve a problem where, a list of numbers are provided, for example
l=[1,2,3,4,3,2,2,3,4,5,6,7,5,4,3,2,2,3,4,3,4,5,6,7]
I need to identify the max occurence of an element, however in case more than 1 element appears the same number of times,
I need to choose the element which is greater in magnitude,
suppose I apply a counter on l and get {1:5,2:5,3:4...}, I have to choose '2' instead of '1'.
Please suggest how to solve this
Edit-
The problem begins like this,
1) a list is provided as an input
l=[1 4 4 4 5 3]
2)I run a Counter on this to obtain the counts of each unique element
3)I need to obtain the key whose value is maximum
4)Suppose the Counter object contains multiple entries whose value is maximum,
as in Counter{1:4,2:4,3:4,5:1}
I have to choose 3 as the key whose value is 4.
5)So far, I have been able to get the Counter object, I have seperated key/value lists using k=counter.keys();v=counter.values()
6)I want to get the indices whose values are max in v
If I run v.index(max(v)), I get the first index whose value matches max value, but I want to obtain the list of indices whose value is max, so that I can obtain corresponding list of keys and obtain max key in that list.
With long lists, using NumPy or any other linear algebra would be helpful, otherwise you can simply use either
l.index(max(l))
or
max(range(len(l)),key=l)
These however return only one of the many argmax's.
So for your problem, you can choose to reverse the array, since you want the maximum that appears later as :
len(l)-l[::-1].index(max(l))-1
If I understood correctly, the following should do what you want.
from collections import Counter
def get_largest_most_freq(lst):
c = Counter(lst)
# get the largest frequency
freq = max(c.values())
# get list of all the values that occur _max times
items = [k for k, v in c.items() if v == freq]
# return largest most frequent item
return max(items)
def get_indexes_of_most_freq(lst):
_max = get_largest_most_freq(lst)
# get list of all indexes that have a value matching _max
return [i for i, v in enumerate(lst) if v == _max]
>>> lst = [3,4,4,2,1,4,6]
>>> get_largest_most_freq(lst)
4
>>> get_indexes_of_most_freq(lst)
[1, 2, 5]
>>> lst = [1,2,3,4,3,2,2,3,4,5,6,7,5,4,3,2,2,3,4,3,4,5,6,7]
>>> get_largest_most_freq(lst)
3
>>> get_indexes_of_most_freq(lst)
[2, 4, 7, 14, 17, 19]

Best way to Sort Python Dictionary by number of same Values

I have a dictionary as follows:
input = {1:'a', 2:'b', 3:'c', 4:'b', 5:'c', 6:'b'}
a - 1 time
b - 3 times
c - 2 times
I want to sort the dictionary in such a way that the value which repeats maximum times will come at fist followed by the value which repeats second most times and so on...
Desired Output
output = {1:'b', 2:'c', 3:'a'}
Please help
Thanks in advance
First of all, you need to realize you do not even care about input dict keys, only about input dict values.
real_input = input.values()
Second of all, you need to count occurences:
counted_items = collections.Counter(real_input)
Third of all, you want to iterate over them in order from most common to least common. .most_common() returns list of (key, count) tuples in expected order.
most_common_in_order = counted_items.most_common()
After that you want to convert that list to dict, with consecutive inegers as keys
result = {i: v for i, (v, _) in zip(itertools.count(1), most_common_in_order)}
Or, in concise form:
result = {i: v for i, (v, _) in zip(itertools.count(1),
collections.Counter(input.values()).most_common())}
Note that dictionaries are inherently not ordered, so actual order is implementation detail, and it's not guaranteed.
from collections import Counter
input = {1: 'a', 2: 'b', 3: 'c', 4: 'b', 5: 'c', 6: 'b'}
output = {index: value for index, (value, _)
in enumerate(Counter(input.values()).most_common(),
start=1)}
print(output)
Edited for Python 3 compatibility.
from collections import Counter
i = {1:'a', 2:'b', 3:'c', 4:'b', 5:'c', 6:'b'}
print (Counter(i.values()))
#Output
Counter({'b': 3, 'c': 2, 'a': 1})

Is it possible to delete keys meeting some criterion using a simple iteration in Python3?

Suppose we have a dict d={"key1":-1,"key2":-2,"key3":3,"key4":0,"key5":-7,"key6":1,...} in python3. Now I want to delete keys whose value is negative, e.g.,"key1":-1,"key2":-2,etc. I tried to write a code like this:
for k in d:
if d[k]<0:
del d[k]
But I received error saying "RuntimeError: dictionary changed size during iteration". From this message, it seems that it is not possible to delete keys of a dictionary meeting some criterion using a simple iteration, so at the moment, I have to save the keys to be deleted in a list, then write another iteration to remove them from d. My question is: is it really impossible to remove some of keys using a single iteration? If it's possible, could you please give a sample code of Python3 that can remove keys meeting some criterion using a simple iteration in Python3? Thank you.
Method #1: use a dictionary comprehension. This doesn't delete so much as replace, but gets you to the same d.
>>> d = {"key1":-1,"key2":-2,"key3":3,"key4":0,"key5":-7}
>>> d = {k: v for k,v in d.items() if v >= 0}
>>> d
{'key3': 3, 'key4': 0}
Method #2: iterate over an independent copy of the keys:
>>> d = {"key1":-1,"key2":-2,"key3":3,"key4":0,"key5":-7}
>>> for k in set(d):
... if d[k] < 0:
... del d[k]
...
>>> d
{'key3': 3, 'key4': 0}
Iterate over the keys instead of the dict:
for k in d.keys():
if d[k]<0:
del d[k]
For this to work in Python 3.X, keys() returns an iterator, so you need to use the following first line:
for k in list(d.keys()):

Resources