here is my code
def common_words(count_dict, limit):
'''
>>> k = {'you':2, 'made':1, 'me':1}
>>> common_words(k,2)
>>> k
{'you':2}
'''
new_list = list(revert_dictionary(count_dict).items())[::-1]
count_dict = {}
for number,word in new_list:
if len(count_dict) + len(word) <= limit:
for x in word:
count_dict[x] = number
print (count_dict)
def revert_dictionary(dictionary):
'''
>>> revert_dictionary({'sb':1, 'QAQ':2, 'CCC':2})
{1: ['sb'], 2: ['CCC', 'QAQ']}
'''
reverted = {}
for key,value in dictionary.items():
reverted[value] = reverted.get(value,[]) + [key]
return reverted
count_dict = {'you':2, 'made':1, 'me':1}
common_words(count_dict,2)
print (count_dict)
what i expected is to have the count_dict variable to change to {'you':2}.
It did work fine in the function's print statement, but not outside the function..
The problem, as others have already written, is that your function assigns a new empty dictionary to count_dict:
count_dict = {}
When you do this you modify the local variable count_dict, but the variable with the same name in the main part of your program continues to point to the original dictionary.
You should understand that you are allowed to modify the dictionary you passed in the function argument; just don't replace it with a new dictionary. To get your code to work without modifying anything else, you can instead delete all elements of the existing dictionary:
count_dict.clear()
This modifies the dictionary that was passed to the function, deleting all its elements-- which is what you intended. That said, if you are performing a new calculation it's usually a better idea to create a new dictionary in your function, and return it with return.
As already mentioned, the problem is that with count_dict = {} you are not changing the passed in dictionary, but you create a new one, and all subsequent changes are done on that new dictionary. The classical approach would be to just return the new dict, but it seems like you can't do that.
Alternatively, instead of adding the values to a new dictionary, you could reverse your condition and delete values from the existing dictionary. You can't use len(count_dict) in the condition, though, and have to use another variable to keep track of the elements already "added" to (or rather, not removed from) the dictionary.
def common_words(count_dict, limit):
new_list = list(revert_dictionary(count_dict).items())[::-1]
count = 0
for number,word in new_list:
if count + len(word) > limit:
for x in word:
del count_dict[x]
else:
count += len(word)
Also note that the dict returned from revert_dictionary does not have a particular order, so the line new_list = list(revert_dictionary(count_dict).items())[::-1] is not guaranteed to give you the items in any particular order, as well. You might want to add sorted here and sort by the count, but I'm not sure if you actually want that.
new_list = sorted(revert_dictionary(count_dict).items(), reverse=True)
just write
return count_dict
below
print count_dict
in function common_words()
and change
common_words(count_dict,2)
to
count_dict=common_words(count_dict,2)
So basically you need to return value from function and store that in your variable. When you are calling function and give it a parameter. It sends its copy to that function not variable itself.
Related
My purpose is to change the value of the elements 3 and 4 to 4 and 3 and I have written a function that takes a list, first number and second number as arguments:
def pre9(the_list, value_to_replace, the_replacing_value):
for i in the_list:
if i == value_to_replace:
value_to_replace = the_replacing_value
elif i == the_replacing_value:
the_replacing_value = value_to_replace
return the_list
I then assign a test-case to a variabel and then print it:
test_pre9 = pre9([1,2,3,4,5,7,3,4], 3, 4)
print(test_pre9)
The result is: [1,2,3,4,5,7,3,4]
I expect it to be: [1,2,4,3,5,7,4,3]
I have for a long time ago written a code that accoplishes this task:
def uppgift_9():
the_list = [3,5,8,9,4,5]
for i in range(len(the_list)-1):
temp = the_list[3]
the_list[3] = the_list[4]
the_list[4] = temp
return the_list
But I've read in many places that using range(len()) is not "pythonic" and it is possible to do anything without using it.
Does anyone know why my code fails?
You don't actually change the item in the list, try this:
def pre9(the_list, value_to_replace, the_replacing_value):
for i, value in enumerate(the_list):
if value == value_to_replace:
the_list[i] = the_replacing_value
elif value == the_replacing_value:
the_list[i] = value_to_replace
return the_list
Now the list will have the actually items changed to what you wanted it to be. Enumerate() returns the index and value of an item in a list, it's very handy! And indeed, the range(len()) is not very pythonic and is usually used when people jump from other languages like Java, C# etc. Using enumerate() is the correct 'pythonic' way of achieving this.
I have a solution to count the number of occurrences of each letter in a string and return a dict.
def count_characters(in_str):
all_freq = {}
for i in in_str:
if i in all_freq:
all_freq[i] += 1
else:
all_freq[i] = 1
return all_freq
count_characters("Hello")
It works.
I am trying to understand how Python automatically assigns each letter as the key to the dict - its not explicitly assigned. I replace the null dictionary assignment with a list and expect to get just the frequency, without the letter.
def count_characters(in_str):
all_freq = []
for i in in_str:
if i in all_freq:
all_freq[i] += 1
else:
all_freq[i] = 1
return all_freq
count_characters("Hello")
I get an error.
TypeError: list indices must be integers or slices, not str
My question is:
How does each letter get automatically assigned as the key?
How can I return just the numbers as a list - without the letter?
How does each letter get automatically assigned as the key?
You are doing it explicitly in all_freq[i] = 1. Here, i contains a letter (though I think the variable could be named better — i typically stands for an idex of some sort, which this isn't).
How can I return just the numbers as a list - without the letter?
You could still build a dictionary and then return list(all_freq.values()). Though, if you do that, how would you know which letter each count corresponds to?
This is probably not relevant for your exercise, but the standard library already has a class for doing this sort of counting: collections.Counter.
List are indexing with integer, in your second exemple you use dictionary synthax with a list, that why python complain.
You can use count method
def count_characters(in_str):
all_freq = []
for i in in_str:
all_freq.append(in_str.count(i))
return all_freq
count_characters("Hello")
Edit : I agree with #NPE comment
You could still build a dictionary and then return list(all_freq.values()). Though, if you do that, how would you know which letter each count corresponds to?
This is probably not relevant for your exercise, but the standard library already has a class for doing this sort of counting: collections.Counter.
It's simple when we use built-in methods of dictionary like .keys(), .values()
Example:
def count_char(string):
dict = {}
count = 0
for i in string :
if i in dict.keys():
dict[i] +=1
else:
dict[i] = 1
for j in dict.values():
count += j
print(dict)
print(count)
I am trying to get shared letters from a string compared to a list of letters. I only return the last letter of l that shares with w . I want all the shared letters instead.
def f(w,l):
common = []
for i in w:
if in i in l:
return common.append(i)
As soon as i is in l your code returns, which immediately exits your function. instead do this:
def f(w,l):
common = []
for i in w:
if i in l:
common.append(i) # no return needed so it will collect all
return common
Make sure you return common at the end your function so you get all the values stored in common.
try this:
def f(w,l):
common = []
for i in w:
if i in l:
common.append(i)
return common
The problem is that the .append method of a list returns None. You were returning from the function the first time you did .append, so you were always going to return None from the function.
I think that what you are really looking for is a list comprehension:
def f(w,l):
return [i for i in w if i in l]
As others have pointed out, you might want to choose more descriptive variable names.
My code is as follows:
self.newMonsterList =[]
myKeys = []
if (len(self.myList)>0):
for i in range(len(self.myList)-1):
myVar = self.myList[i]
myKeys.append(myVar[1])
lis = game.active_entities.keys()
for k in lis:
if (k not in myKeys):
game.active_entities[k].destroy()
for it in self.myList:
if (it[1] in lis):
self.setEnt(it, game.active_entities[it[1]])
else:
self.newMonsterList.append(it)
self.makeEnt()
This code, that is the method in which it is, is called in a while loop which apparently works.
makeEnt appends an Entity with it[1] as Key to self.newMonsterList.
This works, I have tested it. Therefore, an ID which is in newMonsterList after the first full round of all this code (i.e. of the while loop which calls this code) should not be there after the second.
It is, however.
If, on the other hand, I check in makeEnt whether or not the content of newMonsterList already is a key, I get correct results.
I therefore conclude that newMonsterList is not properly emptied in which run of the while-loop.
I have been trying different versions for 2 hors now....anyone got an idea?
I am trying to write that down simpler:
a is a list of Ints
d is a dict with ints as keys
While True:
b=[]
for it in a:
if (it not in d):
b.append(it)
print it
else:
print it
for k in b:
d[k] = k
I found out now that the monsterlist is indeed emptied at each turn, however, in the ifclause ("if (it not in d):"), "it" is appened to the list each turn. However, "it" is also definitely in d after the first iteration, I can print it.
You are aware that this loop iterates over self.myList, but skips the last item in the list, right?
myKeys = []
if (len(self.myList)>0):
for i in range(len(self.myList)-1):
myVar = self.myList[i]
myKeys.append(myVar[1])
lis = game.active_entities.keys()
That seems suspicious to skip the last item.
FYI, I think the above code is equivalent to:
assert self.myList # Because if self.myList was empty, iterating over
# lis (later) would have caused an NameError.
myKeys = [value for key, value in self.myList[:-1]]
lis = game.active_entries.keys()
I have this list:
names = ['john','Jonh','james','James','Jardel']
I want loop over the list and handle consecutive names with a case insensitive match in the same iteration. So in the first iteration I would do something with'john' and 'John' and I want the next iteration to start at 'james'.
I can't think of a way to do this using Python's for loop, any suggestions?
This would be one for itertools.groupby, which groups consecutive equal elements from a list or other iterable. you can specify a function to do the comparison, so that, in your case, the same name in different cases can still be counted as the same thing.
for k, g in itertools.groupby(names, lambda s: s.lower()):
# Example: in the first iteration:
# k = "john"
# g = an iterator over ["john", "John"]
# Process them as you like
names = ['john','John','james','James']
for name, capitalized_name in zip(names[::2], names[1::2]):
print name, capitalized_name
Note that you need an even amount of items for this to work properly.
Or (maybe better; hard to tell with little context) use a set to filter the list to contain only unique names (note that this loses order):
>>> names = ['john','John','james','James','Jardel']
>>> unique_names = set([x.lower() for x in names])
>>> for unique_name in unique_names:
... print unique_name
...
jardel
james
john
You could just use a while loop:
i = 0
while i < len(names):
# compare names[i] with names[i + 1]
i = i + 2 # or + 1 if names not equal, for example
Or are you looking for something a bit more involved?
As you iterate thru the loop, you could try keeping track of the previous name in the list. At the same time, when you're going to store the names, you can make a call to lower() or capitalize() to make the formatting of each name consistent so that you can compare them easier.
e.g.
first = True
prev= ""
for name in names:
if first: #First iteration
prev = name.lower() #Need to get the first elem
do_something_to(curr)
first = False
else:
if prev == name.lower():
print "do nothing"
else:
do_something_to(curr)
prev = name.lower()
May not be the most efficient, but works.
My $0.02:
def byPairs(li):
for i in xrange(1, len(li), 2):
yield (li[i-1], li[i])
for a,b in byPairs(names):
if a.lower()==b.lower():
doSomething(a,b)
I'm not sure I understood the question exactly; what are you trying to accomplish?