python create interchangeable strings - python

lets say I have 2 strings that are interchangeable, like a full word and it's abbreviation: 'max' and 'maximum'
I would like to set it so that they respond the same, for example if i have the following dictionary:
d = {'max':10,'a':5,'b':9}
d['maximum'] will return 10
is this even remotely possible?
note:
these two strings could be 'dog' and 'cat', they do not have to be related.
what I am asking is if I could do something like:
a = 'a' or 'b'
that way the two strings are interchangeable. I do understand that above is not correct syntax, I am just curious if anything like it is possible

You can do that using two dicts:
>>> key_dic = {'maximum':'max', 'minimum':'min'}
>>> d = {'max':10,'a':5,'b':9, 'min':-1}
def get_value(key):
return d[key_dic.get(key, key)]
...
>>> get_value('maximum')
10
>>> get_value('max')
10
>>> get_value('min')
-1
>>> get_value('minimum')
-1

You'll need to convert it into a function, class or something similar.
d_array = {'max':10,'a':5,'b':9}
def d(keyword):
if keyword == "maximum":
keyword = "max"
return d_array[keyword]
>>>print d("maximum")
10

Related

Get a list of values from a list of enumerations

Let us assume that we have an enum class:
class MyEnum(Enum):
foo = 1
bar = 2
How to get the list of values [1, 1, 2] from the above list of enumerations?
mylist = [MyEnum.foo, MyEnum.foo, MyEnum.bar]
I know it is possible to create a new list using list comprehension, but I am wondering if there exists a more natural and straighforward way to get the same output.
we can access name and value of an Enum class by .name, .value. So a simple list comprehension could solve your problem.
class MyEnum(Enum):
foo = 1
bar = 2
mylist = [MyEnum.foo, MyEnum.foo, MyEnum.bar]
my_enum_val_list = [i.value for i in mylist]
Further, you can also use IntEnum to make it behaves just like a simple int array.
class MyEnum(IntEnum):
foo = 1
bar = 2
mylist = [MyEnum.foo, MyEnum.foo, MyEnum.bar]
I could only think about a map:
myvaluelist = list(map(lambda _ : _.value, mylist))
however I think it is much less 'natural' than list comprehesion:
myvaluelist = [_.value for _ in mylist]
[EDIT]
Also comprehesions are quite well optimized, which may be another plus, once one is used to them.
Let's try this:
nb_foo=2
nb_bar=1
mylist1=[MyEnum.foo for i in range(nb_foo)]
mylist2=[MyEnum.bar for i in range(nb_bar)]
mylist = mylist1 + mylist2
print(mylist)
Output
[1, 1, 2]

Is there any Hashable list datatype? [duplicate]

In Java we have HashSet<Integer>, I need similar structure in Python to use contains like below:
A = [1, 2, 3]
S = set()
S.add(2)
for x in A:
if S.contains(x):
print "Example"
Could you please help?
Just use a set:
>>> l = set()
>>> l.add(1)
>>> l.add(2)
>>> 1 in l
True
>>> 34 in l
False
The same works for lists:
>>> ll = [1,2,3]
>>> 2 in ll
True
>>> 23 in ll
False
Edit:
Note #bholagabbar's comment below that the time complexity for in checks in lists and tuples is O(n) on average (see the python docs here), whereas for sets it is on average O(1) (worst case also O(n), but is very uncommon and might only happen if __hash__ is implemented poorly).
In Python, there is a built-in type, set.
The major difference from the hashmap in Java is that the Python set is not typed,
i.e., it is legal to have a set {'2', 2} in Python.
Out of the box, the class set does not have a contains() method implemented.
We typically use the Python keyword in to do what you want, i.e.,
A = [1, 2, 3]
S = set()
S.add(2)
for x in A:
if x in S:
print("Example")
If that does not work for you, you can invoke the special method __contains__(), which is NOT encouraged.
A = [1, 2, 3]
S = set()
S.add(2)
for x in A:
if S.__contains__(x):
print("Example")

use .format() in a string in two steps

I have a string in which I want to replace some variables, but in different steps, something like:
my_string = 'text_with_{var_1}_to_variables_{var_2}'
my_string.format(var_1='10')
### make process 1
my_string.format(var_2='22')
But when I try to replace the first variable I get an Error:
KeyError: 'var_2'
How can I accomplish this?
Edit:
I want to create a new list:
name = 'Luis'
ids = ['12344','553454','dadada']
def create_list(name,ids):
my_string = 'text_with_{var_1}_to_variables_{var_2}'.replace('{var_1}',name)
return [my_string.replace('{var_2}',_id) for _id in ids ]
this is the desired output:
['text_with_Luis_to_variables_12344',
'text_with_Luis_to_variables_553454',
'text_with_Luis_to_variables_dadada']
But using .format instead of .replace.
In simple words, you can not replace few arguments with format {var_1}, var_2 in string(not all) using format. Even though I am not sure why you want to only replace partial string, but there are few approaches that you may follow as a workaround:
Approach 1: Replacing the variable you want to replace at second step by {{}} instead of {}. For example: Replace {var_2} by {{var_2}}
>>> my_string = 'text_with_{var_1}_to_variables_{{var_2}}'
>>> my_string = my_string.format(var_1='VAR_1')
>>> my_string
'text_with_VAR_1_to_variables_{var_2}'
>>> my_string = my_string.format(var_2='VAR_2')
>>> my_string
'text_with_VAR_1_to_variables_VAR_2'
Approach 2: Replace once using format and another using %.
>>> my_string = 'text_with_{var_1}_to_variables_%(var_2)s'
# Replace first variable
>>> my_string = my_string.format(var_1='VAR_1')
>>> my_string
'text_with_VAR_1_to_variables_%(var_2)s'
# Replace second variable
>>> my_string = my_string % {'var_2': 'VAR_2'}
>>> my_string
'text_with_VAR_1_to_variables_VAR_2'
Approach 3: Adding the args to a dict and unpack it once required.
>>> my_string = 'text_with_{var_1}_to_variables_{var_2}'
>>> my_args = {}
# Assign value of `var_1`
>>> my_args['var_1'] = 'VAR_1'
# Assign value of `var_2`
>>> my_args['var_2'] = 'VAR_2'
>>> my_string.format(**my_args)
'text_with_VAR_1_to_variables_VAR_2'
Use the one which satisfies your requirement. :)
Do you have to use format? If not, can you just use string.replace? like
my_string = 'text_with_#var_1#_to_variables_#var2#'
my_string = my_string.replace("#var_1#", '10')
###
my_string = my_string.replace("#var2#", '22')
following seems to work now.
s = 'a {} {{}}'.format('b')
print(s) # prints a b {}
print(s.format('c')) # prints a b c

How to get the first 2 letters of a string in Python?

Let's say I have a string
str1 = "TN 81 NZ 0025"
two = first2(str1)
print(two) # -> TN
How do I get the first two letters of this string? I need the first2 function for this.
It is as simple as string[:2]. A function can be easily written to do it, if you need.
Even this, is as simple as
def first2(s):
return s[:2]
In general, you can get the characters of a string from i until j with string[i:j].
string[:2] is shorthand for string[0:2]. This works for lists as well.
Learn about Python's slice notation at the official tutorial
t = "your string"
Play with the first N characters of a string with
def firstN(s, n=2):
return s[:n]
which is by default equivalent to
t[:2]
Heres what the simple function would look like:
def firstTwo(string):
return string[:2]
In python strings are list of characters, but they are not explicitly list type, just list-like (i.e. it can be treated like a list). More formally, they're known as sequence (see http://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange):
>>> a = 'foo bar'
>>> isinstance(a, list)
False
>>> isinstance(a, str)
True
Since strings are sequence, you can use slicing to access parts of the list, denoted by list[start_index:end_index] see Explain Python's slice notation . For example:
>>> a = [1,2,3,4]
>>> a[0]
1 # first element, NOT a sequence.
>>> a[0:1]
[1] # a slice from first to second, a list, i.e. a sequence.
>>> a[0:2]
[1, 2]
>>> a[:2]
[1, 2]
>>> x = "foo bar"
>>> x[0:2]
'fo'
>>> x[:2]
'fo'
When undefined, the slice notation takes the starting position as the 0, and end position as len(sequence).
In the olden C days, it's an array of characters, the whole issue of dynamic vs static list sounds like legend now, see Python List vs. Array - when to use?
All previous examples will raise an exception in case your string is not long enough.
Another approach is to use
'yourstring'.ljust(100)[:100].strip().
This will give you first 100 chars.
You might get a shorter string in case your string last chars are spaces.
For completeness: Instead of using def you could give a name to a lambda function:
first2 = lambda s: s[:2]

Why doesn't list have safe "get" method like dictionary?

Why doesn't list have a safe "get" method like dictionary?
>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'
>>> l = [1]
>>> l[10]
IndexError: list index out of range
Ultimately it probably doesn't have a safe .get method because a dict is an associative collection (values are associated with names) where it is inefficient to check if a key is present (and return its value) without throwing an exception, while it is super trivial to avoid exceptions accessing list elements (as the len method is very fast). The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you're asking of your list).
Of course, you can easily implement this yourself:
def safe_list_get (l, idx, default):
try:
return l[idx]
except IndexError:
return default
You could even monkeypatch it onto the __builtins__.list constructor in __main__, but that would be a less pervasive change since most code doesn't use it. If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method.
This works if you want the first element, like my_list.get(0)
>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'
I know it's not exactly what you asked for but it might help others.
Probably because it just didn't make much sense for list semantics. However, you can easily create your own by subclassing.
class safelist(list):
def get(self, index, default=None):
try:
return self.__getitem__(index)
except IndexError:
return default
def _test():
l = safelist(range(10))
print l.get(20, "oops")
if __name__ == "__main__":
_test()
Instead of using .get, using like this should be ok for lists. Just a usage difference.
>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'
Credits to jose.angel.jimenez and Gus Bus.
For the "oneliner" fans…
If you want the first element of a list or if you want a default value if the list is empty try:
liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)
returns a
and
liste = []
value = (liste[0:1] or ('default',))[0]
print(value)
returns default
Examples for other elements…
liste = ['a', 'b', 'c']
print(liste[0:1]) # returns ['a']
print(liste[1:2]) # returns ['b']
print(liste[2:3]) # returns ['c']
print(liste[3:4]) # returns []
With default fallback…
liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0]) # returns a
print((liste[1:2] or ('default',))[0]) # returns b
print((liste[2:3] or ('default',))[0]) # returns c
print((liste[3:4] or ('default',))[0]) # returns default
Possibly shorter:
liste = ['a', 'b', 'c']
value, = liste[:1] or ('default',)
print(value) # returns a
It looks like you need the comma before the equal sign, the equal sign and the latter parenthesis.
More general:
liste = ['a', 'b', 'c']
f = lambda l, x, d: l[x:x+1] and l[x] or d
print(f(liste, 0, 'default')) # returns a
print(f(liste, 1, 'default')) # returns b
print(f(liste, 2, 'default')) # returns c
print(f(liste, 3, 'default')) # returns default
Tested with Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
Try this:
>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'
A reasonable thing you can do is to convert the list into a dict and then access it with the get method:
>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')
So I did some more research into this and it turns out there isn't anything specific for this. I got excited when I found list.index(value), it returns the index of a specified item, but there isn't anything for getting the value at a specific index. So if you don't want to use the safe_list_get solution which I think is pretty good. Here are some 1 liner if statements that can get the job done for you depending on the scenario:
>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'
You can also use None instead of 'No', which makes more sense.:
>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None
Also if you want to just get the first or last item in the list, this works
end_el = x[-1] if x else None
You can also make these into functions but I still liked the IndexError exception solution. I experimented with a dummied down version of the safe_list_get solution and made it a bit simpler (no default):
def list_get(l, i):
try:
return l[i]
except IndexError:
return None
Haven't benchmarked to see what is fastest.
Dictionaries are for look ups. It makes sense to ask if an entry exists or not. Lists are usually iterated. It isn't common to ask if L[10] exists but rather if the length of L is 11.
If you
want a one liner,
prefer not having try / except in your happy code path where you needn't, and
want the default value to be optional,
you can use this:
list_get = lambda l, x, d=None: d if not l[x:x+1] else l[x]
Usage looks like:
>>> list_get(['foo'], 4) == None
True
>>> list_get(['hootenanny'], 4, 'ho down!')
'ho down!'
>>> list_get([''], 0)
''
For small index values you can implement
my_list.get(index, default)
as
(my_list + [default] * (index + 1))[index]
If you know in advance what index is then this can be simplified, for example if you knew it was 1 then you could do
(my_list + [default, default])[index]
Because lists are forward packed the only fail case we need to worry about is running off the end of the list. This approach pads the end of the list with enough defaults to guarantee that index is covered.
This isn't an extremely general-purpose solution, but I had a case where I expected a list of length 3 to 5 (with a guarding if), and I was breaking out the values to named variables. A simple and concise way I found for this involved:
foo = (argv + [None, None])[3]
bar = (argv + [None, None])[4]
Now foo and bar are either the 4th and 5th values in the list, or None if there weren't that many values.
Your usecase is basically only relevant for when doing arrays and matrixes of a fixed length, so that you know how long they are before hand. In that case you typically also create them before hand filling them up with None or 0, so that in fact any index you will use already exists.
You could say this: I need .get() on dictionaries quite often. After ten years as a full time programmer I don't think I have ever needed it on a list. :)

Categories