If key contain substring in Python - python

I have a more different type of keys in dict (there is no need to type values too)
'PL-1/KK-1/FO-1'
'PL-1/KK-2/GH-3'
'PL-1/KK-2'
'PL-1/KK-1/FO-4'
And I need a condition
if exist (key.split('/')[2])
do something
return data
else:
do something
return data
Desired output:
In the first condition, all keys make entries except 'PL-1/KK-2'.
Is there in python something like 'exist'?

No, there is no 'exists' operator.
In your case you should just test slashes:
if key.count('/') >= 2:
# ...
If you need to have the components of the key, store and test the length:
components = key.split('/')
if len(components) >= 2:
# ...

def has_key(i_dict, i_filter):
return any(k for k in i_dict.iterkeys() if i_filter(k))
# be it a dict called my_dict
# you could call it like
has_key(my_dict, lambda x: x.count("/") == 2)
# or
has_key(my_dict, lambda x: len(x.split("/"))==2)
here's a little test
>>> my_dict = {"a":1,"c":3}
>>> has_key(my_dict, lambda k:k=="a")
True
>>> has_key(my_dict, lambda k:k=="c")
True
>>> has_key(my_dict, lambda k:k=="x")
False

Related

Find if value exists in multiple list and get names of it

I found similar question, but I'm not able to convert answer to match my needs.
(Find if value exists in multiple lists)
So, basicly, I have multiple lists, and I want to list all of them, which contain current user username.
import getpass
value = getpass.getuser()
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
#No idea how code below works
w = next(n for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), globals().items()) if value in v)
print(w)
If current user is user1, I want it to print rep_WOHTEL, rep_REPDAY and rep_ZARKGL. Code above print only ony of them.
How should I change this part of script, to print all I want?
Like I commented in the linked question, iterating through all of globals() or locals() is a bad idea. Store your lists together in a single dictionary or list, and iterate through that instead.
value = "user1"
named_lists = {
"WOHTEL": ['user1','user2','user3'],
"REPDAY": ['user4','user1','user3'],
"ZARKGL": ['user3','user1','user2'],
"WOHOPL": ['user3','user2','user5']
}
names = [name for name, seq in named_lists.items() if value in seq]
print(names)
Result:
['REPDAY', 'ZARKGL', 'WOHTEL']
Checking if value is in all global lists, and if true, print which list(s) contains the required value.
Code:
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
value = 'user1'
x = globals().items()
for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), x):
if value in v:
print(n)
Output:
rep_REPDAY
rep_ZARKGL
rep_WOHTEL
More info about the used functions:
globals()
dict.items()
filter()
isinstance()
startswith()

How to hash strings in python to match within 1 character?

I've read about LSH hashing and am wondering what is the best implementation to match strings within 1 character?
test = {'dog':1, 'cat': 2, 'eagle': 3}
test['dog']
>> 1
I would want to also return 1 if I lookup test['dogs'] or test['dogg']. I realize that it would also return 1 if I were to look up "log" or "cog", but I can write a method to exclude those results.
Also how can I further this method for general strings to return a match within X characters?
string1 = "brown dogs"
string2 = "brown doggie"
Assuming only string1 is stored in my dictionary, a lookup for string2 would return string1.
Thanks
Well, you can define the similarity between 2 strings by the length of the start they share in common (3 for doga and dogs, for instance). This is simplistic, but that could fit your needs.
With this assumption, you can define this:
>>> test = {'dog':1, 'cat': 2, 'eagle': 3}
>>> def same_start(s1, s2):
ret = 0
for i in range(min(len(s1), len(s2))):
if s1[i] != s2[i]:
break
ret += 1
return ret
>>> def closest_match(s):
return max(((k, v, same_start(k, s)) for k, v in test.iteritems()), key=lambda x: x[2])[1]
>>> closest_match('dogs') # matches dog
1
>>> closest_match('cogs') # matches cat
2
>>> closest_match('eaogs') # matches eagle
3
>>>
Maybe you could try using a Soundex function as your dictionary key?
Since your relation is not 1:1, maybe you could define your own dict type with redefined __getitem__ which could return a list of possible items. Here's what I mean:
class MyDict(dict):
def __getitem__(self, key):
l = []
for k, v in self.items():
if key.startswith(k): # or some other comparation method
l.append(v)
return l
This is just an idea, probably other dict methods should be redefined too in order to avoid possible errors or infinite loops. Also, #Emmanuel's answer could be very useful here if you want only one item returned instead of the list, and that way you wouldn't have to redefine everything.

Python convert string to array assignment

In my application I am receiving a string 'abc[0]=123'
I want to convert this string to an array of items. I have tried eval() it didnt work for me. I know the array name abc but the number of items will be different in each time.
I can split the string, get array index and do. But I would like to know if there is any direct way to convert this string as an array insert.
I would greately appreciate any suggestion.
are you looking for something like
In [36]: s = "abc[0]=123"
In [37]: vars()[s[:3]] = []
In [38]: vars()[s[:3]].append(eval(s[s.find('=') + 1:]))
In [39]: abc
Out[39]: [123]
But this is not a good way to create a variable
Here's a function for parsing urls according to php rules (i.e. using square brackets to create arrays or nested structures):
import urlparse, re
def parse_qs_as_php(qs):
def sint(x):
try:
return int(x)
except ValueError:
return x
def nested(rest, base, val):
curr, rest = base, re.findall(r'\[(.*?)\]', rest)
while rest:
curr = curr.setdefault(
sint(rest.pop(0) or len(curr)),
{} if rest else val)
return base
def dtol(d):
if not hasattr(d, 'items'):
return d
if sorted(d) == range(len(d)):
return [d[x] for x in range(len(d))]
return {k:dtol(v) for k, v in d.items()}
r = {}
for key, val in urlparse.parse_qsl(qs):
id, rest = re.match(r'^(\w+)(.*)$', key).groups()
r[id] = nested(rest, r.get(id, {}), val) if rest else val
return dtol(r)
Example:
qs = 'one=1&abc[0]=123&abc[1]=345&foo[bar][baz]=555'
print parse_qs_as_php(qs)
# {'abc': ['123', '345'], 'foo': {'bar': {'baz': '555'}}, 'one': '1'}
Your other application is doing it wrong. It should not be specifying index values in the parameter keys. The correct way to specify multiple values for a single key in a GET is to simply repeat the key:
http://my_url?abc=123&abc=456
The Python server side should correctly resolve this into a dictionary-like object: you don't say what framework you're running, but for instance Django uses a QueryDict which you can then access using request.GET.getlist('abc') which will return ['123', '456']. Other frameworks will be similar.

Pythonic way to fetch all elements in a dictionary, falling between two keys?

I have a dictionary object, and I want to extract a subset of the dictionary (i.e. return another dictionary), which contains all elements of the parent dictionary where the key matches a certain criteria.
For example:
parent_dict = {1: 'Homer',
2: 'Bart',
3: 'Lisa',
4: 'Marge',
5: 'Maggie'
}
def filter_func(somedict, key_criteria_func):
pass
I want to write (in a pythonic way), filter_func, so that I can call it like this:
filter_func(parent_dict, ">2 and <4")
which will return the new dict:
{ 3: 'Lisa' }
What is the most pythonic way to write filter_func?
To keep things simple, I will limit the criteria to simple boolean operations.
[[Edit]]
This is the output when I try the following command:
>>> {key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
File "<stdin>", line 1
{key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
^
SyntaxError: invalid syntax
BTW, I'm running Python 2.6.5
Solution
Starting from python 2.7, you can use dictionary comprehension. There are like list comprehensions, but applied to a dictionary:
>>> parent_dict = {1: 'Homer',
... 2: 'Bart',
... 3: 'Lisa',
... 4: 'Marge',
... 5: 'Maggie'
... }
>>> {key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
1: {3: 'Lisa'}
You probably don't need to make it a function, but if you do, you can just use a lambda function as a filter:
>>> def filter_func(somedict, key_criteria_func):
... return {k:v for k, v in somedict.iteritems() if key_criteria_func(k)}
...
... filter_func(parent_dict, lambda x: 2 < x < 4)
2: {3: 'Lisa'}
For Python 2.6.5 and all version before 2.7, replace the dict comprehension with:
dict((k,v) for k,v in parent_dict.iteritems() if 2 < k < 4)
Why a lambda function ?
Lambda function are not magic, it's just a way to easily create fonction on the fly. You can do everything you do with lambda witout it, the only difference is that lambdas are expression, and therefor can be used directly between parenthis.
Compare:
>>> func = lambda x: 2 < x < 4
>>> func(3)
True
With:
>>> def func(x):
... return 2 < x < 4
...
>>> func(3)
True
It's exactly the same and produce the same function, except the lambda function won't have a name. But you don't care, on your case you don't need a name, you just need a reference to call it, and the variable func contains this reference.
The lambda syntax is weird because:
You don't need parenthesis for the parameters (you don't even need parameter)
you don't do def var(param): but var = lambda param:. Nothing magic, it's just syntax
you can't make a 2 lines lambda: the return result must fit in one instruction.
you don't use the return keyword: the right part of the lambda is returned automatically
Now the nice thing with a lamda, is that since it's an expression, you can use it between parenthese, meaning you can create and pass your fonction à the same time.
Compare:
>>> filter_func(parent_dict, lambda x: 2 < x < 4)
With:
>>> def func(x):
... return 2 < x < 4
...
>>> filter_func(parent_dict, func)
It's exactly the same. The lambda is just shorter.
The hard part here is to understand that you can pass a function as a parameter in Python because everything in Python is an object, including functions.
You can even do this:
>>> def func():
... print "test"
...
>>> ref_to_func = func # assign the function refence to another var
>>> del func # delete this label
>>> ref_to_func() # call the function from this label
test
And you can even define a fonction on one line:
>>> def func(): print "test"
>>> func()
test
But you can't do this:
filter_func(parent_dict, def func(x): 2 < x 4 )
Which is where lambdas are useful.
dict((k,v) for k,v in parent_dict.iteritems() if 2 < k < 4)
This works for Python 2.6.5.
for python 2.5.2:
dict( (k,v) for k,v in parent_dict.iteritems() if k > 2 and k < 4 )

Map list onto dictionary

Is there a way to map a list onto a dictionary? What I want to do is give it a function that will return the name of a key, and the value will be the original value. For example;
somefunction(lambda a: a[0], ["hello", "world"])
=> {"h":"hello", "w":"world"}
(This isn't a specific example that I want to do, I want a generic function like map() that can do this)
In Python 3 you can use this dictionary comprehension syntax:
def foo(somelist):
return {x[0]:x for x in somelist}
I don't think a standard function exists that does exactly that, but it's very easy to construct one using the dict builtin and a comprehension:
def somefunction(keyFunction, values):
return dict((keyFunction(v), v) for v in values)
print somefunction(lambda a: a[0], ["hello", "world"])
Output:
{'h': 'hello', 'w': 'world'}
But coming up with a good name for this function is more difficult than implementing it. I'll leave that as an exercise for the reader.
If I understand your question correctly, I believe you can accomplish this with a combination of map, zip, and the dict constructor:
def dictMap(f, xs) :
return dict(zip(map(f, xs), xs)
And a saner implementation :
def dictMap(f, xs) :
return dict((f(i), i) for i in xs)
Taking hints from other answers I achieved this using map operation. I am not sure if this exactly answers your question.
mylist = ["hello", "world"]
def convert_to_dict( somelist ):
return dict( map( lambda x: (x[0], x), somelist ) )
final_ans = convert_to_dict( mylist )
print final_ans
If you want a general function to do this, then you're asking almost the right question. Your example doesn't specify what happens when the key function produces duplicates, though. Do you keep the last one? The first one? Do you actually want to make a list of all the words that start with the same letter? These questions are probably best answered by the user of the function, not the designer.
Parametrizing over these results in a more complicated, but very general, function. Here's one that I've used for several years:
def reduce_list(key, update_value, default_value, l):
"""Reduce a list to a dict.
key :: list_item -> dict_key
update_value :: key * existing_value -> updated_value
default_value :: initial value passed to update_value
l :: The list
default_value comes before l. This is different from functools.reduce,
because functools.reduce's order is wrong.
"""
d = {}
for k in l:
j = key(k)
d[j] = update_value(k, d.get(j, default_value))
return d
Then you can write your function by saying:
reduce_list(lambda s:s, lambda s,old:s[0], '', ['hello', 'world'])
# OR
reduce_list(lambda s:s, lambda s,old: old or s[0], '', ['hello', 'world'])
Depending on whether you want to keep the first or last word starting with, for example, 'h'.
This function is very general, though, so most of the time it's the basis for other functions, like group_dict or histogram:
def group_dict(l):
return reduce_list(lambda x:x, lambda x,old: [x] + old, [], l)
def histogram(l):
return reduce_list(lambda x:x, lambda x,total: total + 1, 0, l)
>>> dict((a[0], a) for a in "hello world".split())
{'h': 'hello', 'w': 'world'}
If you want to use a function instead of subscripting, use operator.itemgetter:
>>> from operator import itemgetter
>>> first = itemgetter(0)
>>> dict((first(x), x) for x in "hello world".split())
{'h': 'hello', 'w': 'world'}
Or as a function:
>>> dpair = lambda x : (first(x), x)
>>> dict(dpair(x) for x in "hello world".split())
{'h': 'hello', 'w': 'world'}
Finally, if you want more than one word per letter as a possibility, use collections.defaultdict
>>> from collections import defaultdict
>>> words = defaultdict(set)
>>> addword = lambda x : words[first(x)].add(x)
>>> for word in "hello house home hum world wry wraught".split():
addword(word)
>>> print words['h']
set(['house', 'hello', 'hum', 'home'])

Categories