Slicing strings in a comprehension - python

I'm I need to slice the leading character off the valued a dictionary - but only if the length of the value is greater than 1. Currently I'm doing this with a dictionary comprehension:
new_dict = {item[0]:item[1][1:] for item in old_dict if item.startswith('1')}
but I don't know how to modify this so that keys of length one are left alone.
The keys are the codewords of a Huffman code, and so start with '0' or '1'.
An example code is:
code = {'a':'0', 'b':'10', 'c':'110', 'd':'111'}
The above code works fine for 'b','c','d' but fails for 'a' (this is intensional - it's a unit test).
How do I correctly modify the above example to pass the test?

The nature of a comprehension is that it builds a new object iteratively, so you if you want every key in the original object old_dict to have a corresponding key in new_dict, you simply have to process every key.
Also, you say "I need to slice the leading character off the keys a dictionary", but the code you give slices the leading characters off the values. I assume you mean values. I suggest the following:
new_dict = {key:(value[:1] if len(value) > 1 else value) for key,value in old_dict.iteritems()}
Apart from using sequence assignment to make the iteration a bit clearer, I've used the if expression (equivalent to ternary operator in c-like languages) to incorporate the condition.
I've also dropped your original if clause, because I don't understand you to want to skip values starting with '1'.

I'm not sure which variable is where but you could do something along these lines.
new_dict = { item[0]:item[1][1] if len(item[1]) > 1 else item[0]:item[1] for item in old_dict if item.startswith('1') }

If I understand your question correctly, you can accomplish it with this:
new_dict = {k:v[len(v)>1:] for k,v in old_dict.items()}
v[len(v)>1] will return the key if it is only 1 character, and it will strip off the leading character if it is more than one character
I'm not sure what you are trying to accomplish with if item.startswith('1') is a qualifier for your list comprehension but if you need it you can add it back on. May need to make it v.startswith('1') though.

Related

I am trying to implement flames game in python.Not able to remove all matching character?

def flames(l,l1):
for i in l:
if i in l1:
l.remove(str(i))
l1.remove(str(i))
n1=input("Enter first name:")
n2=input("Enter Second name:")
l=list(n1)
l1=list(n2)
flames(l,l1)
print(l)
print(l1)
I didn't completed my code entirely.But i am done with removing matched character.But the problem is its removing only first matched character.It's not removing remaining match characters.What is the problem in my code?
You might find it easier to use a dict instead of a list to keep track of the letters left in each name. For instance, if the name is "Billy", the dict would be: {"b":1, "i":1, "l":2, "y":1}. In this way you can easily remove all instances of the letter because they're all stored in the same location.
Easiest way to create the dictionaries for each name would be dictionary comprehension:
n1 = input("Enter first name: ").lower()
d1 = { char:n1.count(char) for char in n1 }
Of course, the order of these letters doesn't matter and will likely appear in a different order. Also notice that the "B" in "Billy" becomes "b" in the dictionary. This might be a matter of preference for purposes of this game, but generally you would want to convert all characters to lowercase so upper and lower case letters are not treated as distinct.
There's one more thing to consider when using a dict rather than a list to store the characters: you can't modify the dictionary as you're iterating over it, you'll get a RuntimeError. So as you're iterating through d1 (the characters in the first name) and deleting the matching characters in d2, you'll have to remember the matched characters so you can delete them from d1 later.
d1ToDel = []
for k in d1:
if k in d2:
del d2[k]
d1ToDel.append(k)
for k in d1ToDel:
del d1[k]
After that, you just have to sum up the values remaining in each dictionary, which will give you the remaining number of characters after removing all matches. And then do a little modulo arithmetic to figure out which of the "Flames" characters the pair will land on.

How to compare a python dictionary key with a part of another dictionary's key? something like a .contains() function

Most of my small-scale project worked fine using dictionaries, so changing it now would basically mean starting over.
Let's say I have two different dictionaries(dict1 and dict2).
One being:
{'the dog': 3, 'dog jumped': 4, 'jumped up': 1, 'up onto': 8, 'onto me': 13}
Second one being:
{'up': 12, 'dog': 22, 'jumped': 33}
I want to find wherever the first word of the first dictionary is equal to the word of the second one. These 2 dictionaries don't have the same length, like in the example. Then after I find them, divide their values.
So what I want to do, sort of using a bit of Java is:
for(int i = 0;i<dict1.length(),i++){
for(int j = 0;j<dict2.length(),j++){
if(dict1[i].contains(dict2[j]+" ") // not sure if this works, but this
// would theoretically remove the
// possibility of the word being the
// second part of the 2 word element
dict1[i] / dict2[j]
What I've tried so far is trying to make 4 different lists. A list for dict1 keys, a list for dict1 values and the same for dict2. Then I've realized I don't even know how to check if dict2 has any similar elements to dict1.
I've tried making an extra value in the dictionary (a sort of index), so it would kind of get me somewhere, but as it turns out dict2.keys() isn't iterable either. Which would in turn have me believe using 4 different lists and trying to compare it somehow using that is very wrong.
Dictionaries don't have any facilities at all to handle parts of keys. Keys are opaque objects. They are either there or not there.
So yes, you would loop over all the keys in the first dictionary, extract the first word, and then test if the other dictionary has that first word as a key:
for key, dict1_value in dict1.items():
first_word = key.split()[0] # split on whitespace, take the first result
if first_word in dict2:
dict2_value = dict2[first_word]
print(dict1_value / dict2_value)
So this takes every key in dict1, splits off the first word, and tests if that word is a key in dict2. If it is, get the values and print the result.
If you need to test those first words more often, you could make this a bit more efficient by first building another structure to to create an index from first words to whole keys. Simply store the first words every key of the first dictionary, in a new dictionary:
first_to_keys = {}
for key in dict1:
first_word = key.split()[0]
# add key to a set for first_word (and create the set if there is none yet)
first_to_keys.setdefault(first_word, set()).add(key)
Now first_to_key is a dictionary of first words, pointing to sets of keys (so if the same first word appears more than once, you get all full keys, not just one of them). Build this index once (and update the values each time you add or remove keys from dict1, so keep it up to date as you go).
Now you can compare that mapping to the other dictionary:
for matching in first_to_key.keys() & dict2.keys():
dict2_value = dict2[matching]
for dict1_key in first_to_key[matching]:
dict1_value = dict1[dict1_key]
print(dict1_value / dict2_value)
This uses the keys from two dictionaries as sets; the dict.keys() object is a dictionary view that lets you apply set operations. & gives you the intersection of the two dictionary key sets, so all keys that are present in both.
You only need to use this second option if you need to get at those first words more often. It gives you a quick path in the other direction, so you could loop over dict2, and quickly go back to the first dictionary again.
Here's a solution using the str.startswith method of strings
for phrase, val1 in dict1.items():
for word, val2 in dict2.items():
if phrase.startswith(word):
print(val1/val2)

Python > passing variables of a string into a method

I'm looking to replace a list of characters (including escaped characters) with another.
for example:
l=['\n','<br>','while:','<while>','for:','<for>']
s='line1\nline2'
s.replace(l[0],[l[1])
but passing the list indices through the method produces no effect.
I've also tried using
s=l[1].join(s.split(l[0]))
How can I replace a list of characters with another without expressing the pairs each time in the function?
As I said in the comments, the problem with your code is that you assumed that the replace works in-place. It does not, you have to assign the value it returns to the variable.
But, there is a better way of doing it that involves dictionaries. Take a look:
d = {'\n': '<br>', 'while:': '<while>', 'for:': '<for>'}
s = 'line1\nline2\nwhile: nothing and for: something\n\nnothing special'
for k, v in d.items():
s = s.replace(k, v)
print(s) # line1<br>line2<br><while> nothing and <for> something<br><br>nothing special
The advantage of using dictionaries in this case is that you make it very straightforward what you want to replace and what with. Playing with the indexes is not something you want to do if you can avoid it.
Finally, if you are wondering how to convert your list to a dict you can use the following:
d = {k: v for k, v in zip(l[::2], l[1::2])}
which does not break even if your list has an odd number of elements.
l=['\n','<br>','while:','<while>','for:','<for>']
s='line1\nline2'
for i in range(0, len(l), 2):
s = s.replace(l[i], l[i+1])
You simply have to iterate over the list containing your desired pairs, stepping over 2 values each time. And then assign the result of the replacement to the variable itself (replace doesn't do inline replacement because strings are inmutable in Python)

finding first item in a list whose first item in a tuple is matched

I have a list of several thousand unordered tuples that are of the format
(mainValue, (value, value, value, value))
Given a main value (which may or may not be present), is there a 'nice' way, other than iterating through every item looking and incrementing a value, where I can produce a list of indexes of tuples that match like this:
index = 0;
for destEntry in destList:
if destEntry[0] == sourceMatch:
destMatches.append(index)
index = index + 1
So I can compare the sub values against another set, and remove the best match from the list if necessary.
This works fine, but just seems like python would have a better way!
Edit:
As per the question, when writing the original question, I realised that I could use a dictionary instead of the first value (in fact this list is within another dictionary), but after removing the question, I still wanted to know how to do it as a tuple.
With list comprehension your for loop can be reduced to this expression:
destMatches = [i for i,destEntry in enumerate(destList) if destEntry[0] == sourceMatch]
You can also use filter()1 built in function to filter your data:
destMatches = filter(lambda destEntry:destEntry[0] == sourceMatch, destList)
1: In Python 3 filter is a class and returns a filter object.

Removing one element from an entire dictionary

I've been working on this thing for hours, still cant figure it out :O
The problem I'm having is this. Lets say I have a dictionary with 4-element tuples as elemets and an integer as key. When an element is removed from the whole dictionary (which belongs to every tuple) making two of the tuples (elements) same, the keys of the two tuples don't add up. Instead, a new element is formed, with the key for that element being one of the previous 2 keys.
Let's say I have a dictionary:
dict={('A','B','D','C'): 4, ('C','B','A','D'):5, ('D','A','C','B'):3,('D','A','B','C'):1}
Now I wanna remove one letter from the entire dictionary.
for example, If I wanna remove 'B'. The following new dictionary is formed, but isn't returned, because two of the elements are the same.
{('A','D','C'): 4, ('C','A','D'):5, ('D','A','C'):3,('D','A','C'):1}
Instead of ('D','A','C'):3,('D','A','C'):1 becoming ('D','A','C'):4, this is what ends up happenening:
('D','A','C'):3 along with other tuples
So basically, one of the tuples disappears.
This is the method I'm currently using:
for next in dict:
new_tuple=()
for i in next:
if i!='A':
new_tuple+=(i,)
new_dict[new_tuple]=dict[next]
The above code returns new_dict as the following:
{('A','D','C'): 4, ('C','A','D'):5, ('D','A','C'):3}
So what can I do, to remove one letter from every tuple in the entire dictionary, and if two of the tuples look the same, they merge and the keys add up?
You will have to rebuild your entire dictionary, as each key/value pair is going to be affected. You can use a defaultdict to make the merging easier when you encounter now-overlapping keys:
from collections import defaultdict
new_dict = defaultdict(int)
for key, value in old_dict.items():
new_key = tuple(i for i in key if i != 'A')
new_dict[new_key] += value
Because when first looking up new_key in new_dict it'll be set to 0 by default, all we have to do is add the old value to update new_dict for when we first encounter a key. The next time we encounter the key the values are 'merged' by adding them up.

Categories

Resources