Initialising Python dictionary with list comprehension - python-3.x

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.

Related

Can someone explain the logic behind this code?

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.

TypeError: list indices must be integers or slices, not str. While selecting item from loop for

I´ve been trying for a while to select an item from a list with the variable of the for loop. But I keep getting this error:
TypeError: list indices must be integers or slices, not str
The issue dissapears when I change the i for a number, but that's not what I want to do. I´ve been looking for similar issues but couldn't manage to get it working. Advise please.
I want this to result as: ['p1', 'q1', 'p2', 'q2', 'p3', 'q3', 'p4', 'q4', 'p5', 'q5']
listcont=[]
cont=0
while cont<=5:
for i in list:
listcont.append(list[i]+str(cont))
cont+=1
return listcont
n=5
list=['q','p']
print(concat(list,n))´´´
First, when you write for i in list you're already iterating over the elements of the list, not the indices. So you can use the item directly:
listcont.append(i + str(cont))
Second, you shouldn't name things list since it shadows the built-in of that name and will cause all kinds of trouble.
Third, the while loop would be better written as a for with a range
n = 5
my_list = ['q', 'p']
listcont = []
for counter in range(1, n+1):
for item in my_list:
listcont.append(item + str(counter))
Finally, you can simplify all of this into a list comprehension and make it look neater with an f-string:
def make_list(my_list, limit):
return [f'{item}{counter}' for counter in range(1, limit+1) for item in my_list]
make_list(['p', 'q'], 5)
When you use for loop, you must know that if you are using for i in list it means that i here is the element of the list, and the loop will traverse each element of the list.
While, what you want to do is for i in range(len(list)), this will traverse the list with i as a number which can gain a value, less than or equal to len(list) - 1.
You can learn this very basic thing about for loop here and hold yourself back from asking such questions.
Hope it helps, thanks.
You have a variable called list which is a bad idea because list is the type of a list in Python. But this isn't the issue. I'm guessing the function you have there, which is missing the declaration, is the function def concat(list, n), and you intended to write while cont <= n.
If all this is the case, when you do
for i in list:
i is going to be members of the list, so 'q', then 'p'. In this case list['p'] doesn't make any sense.
To get the output you're going for I would do (to be easy to read):
def concat(lst, n):
result = []
for i in range(n):
for v in lst:
result.append('{}{}'.format(v, i+1))
return result
You could do the whole thing in one line with:
['{}{}'.format(value, count + 1) for count in range(n) for value in lst]

the code that i've wrote works fine with a list of four elements but when the length of the list increases it is not giving the right answer

I'm trying to write a python code for a problem wherein I will be given with a list of string characters for example ["A", "B", "B", "C"] and the output that I should get is B and if there are more than one repeated value with equal number of repetitions or no elements in the list it should give"NONE" AS output. and my code is doing good so far but when the size of the list is increasing my code is giving wrong output please help me in optimizing the code so that it takes a list of any size and gives a correct output
lis = ["A","B","B","A"] #INPUT LIST
catch = []
final_catch=[]
for i in range(len(lis)):
for j in range(i + 1, len(lis)):
if lis[i] == lis[j]:
catch.append(lis[i])
final_catch =list(set(catch))
print(final_catch)
if len(final_catch)>=2 or len(final_catch) == 0:
print("NONE")
else:
print(final_catch.pop())
for input ["A,"B","B","A"] expected output:"NONE" actual output: "NONE"
for input ["A","A","A","A"] expected output :"A" actual output : "A"
for input ["A","A","B","B","A","B","A","B","B"] expected output : "B"
Try this,
>>> from collections import Counter
>>> l = ["A","A","B","B","A","B","A","B","B"]
>>> d = Counter(l)
>>> result = d.most_common() # result looks like [('B', 5), ('A', 4)]
Output:
>>> result[0][0] if result[0][1] >2 else 'None' # conditional if-else statement
'B'
Explanation:
Use Counter to get number of occurrences of each element in a list
Use .most_common() to get list of most occurrence in the form of tuplesi.e., [(element, no. of occurrence)]
Return a list of the n most common elements and their counts from the
most common to the least
result[0][0] - we are passing index values to get first element of tuple in list.
result[0][1] - This gives you second element of tuple in a list.
*result[0] - select first element in a list

2d plotter witout using any packages

Say we have 10x10 pixels(as coordinates) and we want to plot the data.
Before working with 10x10 instead i started off with 3x3. The point of that project is say we have coordinate(1,2) we put a start at that point. I figured to set my coordinates as dictionary. Then i used two loops. My codes are below
i get the error keyerror:0
File "/home/caglar/temp.py", line 6, in
if dict[i]!=j:
KeyError: 0
dict={1:3,2:1,3:1}
xarr=[]
yarr=[]
for i in range(0,3):
for j in range(0,3):
if dict[i]!=j:
xarr.append("") and yarr.append("")
j+=1
else:
xarr[i].append("*") and yarr[j].append("*")
i+=1
print(xarr)
Your dictionary, dict={1:3,2:1,3:1}, has keys 1, 2, 3. However, you access it with dict[i] != j. i in range(0,3) means "loop through a series of i values starting at 0 and ending before 3". So it will go through 0, 1, 2. This means that when it tries to access the key 0 in your dictionary it can't find it and so raises a KeyError saying that it can't find 0.
Unrelated to your question, you also have some rather odd lines of code there which don't quite make sense:
for i in range(0,3) iterates through values of i, so you don't have to do i += 1 each time. In your code i += 1 and j += 1 don't actually do anything.
and is a boolean operator. It evaluates the boolean statements on either side and tells you if both are true. Pretty much anything can be interpreted as a boolean statement so it doesn't throw an error. But when you're doing xarr.append("") and yarr.append("") you're telling it to evaluate each of the appends, interpret them as booleans, and return the the boolean value of xarr.append("") and yarr.append("). To simply do both things you put each expression on its own line:
xarr.append("")
yarr.append("")
xarr.append("") appends an empty string to the xarr array. If you start with xarr = [] and then do xarr.append("") you'd end up with [""]. If you did it again you'd get ["", ""] and so on. When you do xarr[i].append("*") you're saying "access the i-th item in xarr and then append "*" to it". However, since the items in xarr aren't arrays, you can't append to them so it will error.

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})

Resources