I'm looking for a single expression, mutates an element and returns the modified list
The following is a bit verbose
# key=0; value=3; rng=[1,2]
[(v if i != key else value) for i, v in enumerate(rng)]
Edit:
I'm looking for a way to inline the following function in a single expression
def replace(rng: List, key: int, value):
a = list(rng)
a[key] = value
return a
Edit 2: the code that actually motivated this question
class TextDecoder(nn.Module):
def forward(self, x: Tensor, kv_cache: Tensor):
kv_cache_write = torch.zeros((_:=list(kv_cache.shape))).__setitem__(-2, x.shape[-1]) or _)
...
Maybe better than list concatenation:
[*rng[:key], value, *rng[key+1:]]
Another:
[a for a, a[key] in [(rng[:], value)]][0]
Or if you are just assigning the result to a variable (as discussed) you can do:
a, a[key] = rng[:], value
Try list concatenation:
key = 0
value = 3
rng = [1, 2]
out = rng[:key] + [value] + rng[key+1:]
print(out)
rng[:key] is a copy of the list up to the key (exclusive), [value] is a new list where the only element is value, and rng[key+1] is a copy of the list from the key on (exclusive). Concatenate these together, and you get a copy where the key is replaced.
# key=0; value=3; rng=[1,2]
print(rng.__setitem__(key, value) or rng)
If you don't want to modify the original list rng, you can do
print((_:=list(rng)).__setitem__(key, value) or _)
unfortunately this leaks the variable _.
Related
why this code isn't working? trying to get returns on items which value==key
L=[0,2,2,1,5,5,6,10]
x=dict(enumerate(L))
y=(filter(x.keys()==x.values(), x.items()))
print(list(y))
The keys() method returns a view of all of the keys.
The values() method returns a view of all of the values.
So, x.keys()==x.values() is asking whether all of the keys equal all of the values, which is of course not true.
Also, filter wants a function. But you're not passing it a function, you're just passing it the result of x.keys()==x.values(), or False. To turn that into a function, you'd need to use def or lambda to create a new function.
The function you want to create is a function that takes an item, and returns true if the key equals the value. Since an item is just a 2-element tuple with the key and value for that item, the function to check that is:
y = filter((lambda item: item[0] == item[1]), x.items())
Or, if that's a bit too confusing, don't try to write it inline; just def it separately:
def key_equals_value(item):
key, value = item
return key == value
y = filter(key_equals_value, x.items())
However, this is pretty clumsy; it's much easier to write it as a comprehension than a filter call:
y = ((key, value) for (key, value) in x.items() if key == value)
As a general rule, whenever you don't already have a function to pass to filter or map, and would have to create one with def or lambda, a comprehension will usually be more readable, because you can just write the expression directly.
And, if you want a list rather than a generator, you can do that with a comprehension just by changing the parens to square brackets:
y = [(key, value) for (key, value) in x.items() if key == value]
And, if you want just the values, not the key-value pairs:
y = [value for (key, value) in x.items() if key == value]
If you find yourself confused by comprehensions, they can always be converted into nested statements, with an append at the bottom. So, that last one is equivalent to:
y = []
for key, value in x.items():
if key == value:
y.append(value)
Also, you don't really need a dict here in the first place; you just want to iterate over the index, value pairs. So:
y = [value for (index, value) in enumerate(L) if index == value]
Let's assume that there is a dictionary list like this one:
lst = {(1,1):2, (1,2):5, (1,3):10, (1,4):14, (1,6):22}
I want a simple (the most efficient) function that returns the dictionary key which its value is the maximum.
For example:
key_for_max_value_in_dict(lst) = (1,6)
because the tuple (1,6) has the most value (22).
I came up with this code which might be the most efficient one:
max(lst, key=lambda x: lst[x])
Use a comprehension for that like:
Code:
max((v, k) for k, v in lst.items())[1]
How does it work?
Iterate over the items() in the dict, and emit them as tuples of (value, key) with the value first in the tuple. max() can then find the largest value, because tuples sort by each element in the tuple, with first element matching first element. Then take the second element ([1]) of the max tuple since it is the key value for the max value in the dict.
Test Code:
lst = {(1,1):2, (1,2):5, (1,3):10, (1,4):14, (1,6):22}
print(max((v, k) for k, v in lst.items())[1])
Results;
(1, 6)
Assuming you're using a regular unsorted dictionary, you'll need to walk down the entire thing once. Keep track of what the largest element is and update it if you see a larger one. If it is the same, add to the list.
largest_key = []
largest_value = 0
for key, value in lst.items():
if value > largest_value:
largest_value = value
largest_key = [key]
elif value == largest_value:
largest_key.append(key)
I have to convert a bunch of strings into numbers, process the numbers and convert back.
I thought of a map where I will add 2 keys when I've provided string:
Key1: (string, number);
Key2: (number, string).
But this is not optimal in terms of memory.
What I need to archieve in example:
my_cool_class.get('string') # outputs 1
my_cool_class.get(1) # outputs 'string'
Is there better way to do this in python?
Thanks in advance!
You can implement your own twoway dict like
class TwoWayDict(dict):
def __len__(self):
return dict.__len__(self) / 2
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
dict.__setitem__(self, value, key)
my_cool_class = TwoWayDict()
my_cool_class[1] = 'string'
print my_cool_class[1] # 'string'
print my_cool_class['string'] # 1
Instead of allocate another memory for the second dict, you can get the key from the value, consider that it will cost you with run-time.
mydict = {'george':16,'amber':19}
print (mydict.keys()[mydict.values().index(16)])
>>> 'george'
EDIT:
Notice that In Python 3, dict.values() (along with dict.keys() and dict.items()) returns a view, rather than a list. You therefore need to wrap your call to dict.values() in a call to list like so:
mydict = {'george':16,'amber':19}
print (list(mydict.keys())[list(mydict.values()).index(16)])
If optimal memory usage is an issue, you may not want to use Python in the first place. To solve your immediate problem, just add both the string and the number as keys to the dictionary. Remember that only a reference to the original objects will be stored. Additional copies will not be made:
d = {}
s = '123'
n = int(s)
d[s] = n
d[n] = s
Now you can access the value by the opposite key just like you wanted. This method has the advantage of O(1) lookup time.
You can create a dictionary of tuples this way you just need to check against the type of the variable to decide which one you should return.
Example:
class your_cool_class(object):
def __init__(self):
# example of dictionary
self.your_dictionary = {'3': ('3', 3), '4': ('4', 4)}
def get(self, numer):
is_string = isinstanceof(number, str)
number = str(number)
n = self.your_dictionary.get(number)
if n is not None:
return n[0] if is_string else n[1]
>>>> my_cool_class = your_cool_class()
>>>> my_cool_class.get(3)
>>>> '3'
>>>> my_cool_class.get('3')
>>>> 3
I have a list of lists in python of the form
A=[[1,2,3,4],
[5,6,7,8],
[9,10,11,12]]
I need to get a fast way to get the row index of an element in that structure.
method(2) = 0
method(8) = 1
method(12) = 2
and so on. As always, the fastest the method the better, as my actual list of lists is quite large.
In this state, the data structure (list of lists) is not quite convenient and efficient for the queries you want to make on it. Restructure it to have it in a form:
item -> list of sublist indexes # assuming items can be present in multiple sublists
This way the lookups would be instant, by key - O(1). Let's use defaultdict(list):
>>> from collections import defaultdict
>>>
>>> d = defaultdict(list)
>>> for index, sublist in enumerate(A):
... for item in sublist:
... d[item].append(index)
...
>>> d[2]
[0]
>>> d[8]
[1]
>>> d[12]
[2]
It is very simple using next() with a generator expression:
def method(lists, value):
return next(i for i, v in enumerate(lists) if value in v)
The problem with that is that it will have an error if value does not occur. With a slightly longer function call, you can make a default of -1:
def method(lists, value):
return next((i for i,v in enumerate(lists) if value in v), -1)
Here is another way using numpy
import numpy
A = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
my_array = numpy.array(A)
numpy.where(my_array==2) ## will return both the list and the index within the list
numpy.where(my_array==12)
## As a follow up if we want only the index we can always do :
numpy.where(my_array==12)[0][0] # will return 2 , index of list
numpy.where(my_array==12)[1][0] # will return 3 , index within list
find operation in list is linear. Following is simple code in python to find an element in list of lists.
A=[[1,2,3,4],
[5,6,7,8],
[9,10,11,12]]
def method(value):
for idx, list in enumerate(A):
if value in list:
return idx
return -1
print (method(12))
Suppose that I have dictionary with 3 keys 'x', 'y' and 'z'. What I need to do is to write a function that, given 'x' as argument, swaps the values stored in 'y' and 'z'.
def swap(d, key):
a, b = [_ for _ in d if _ != key]
d[a], d[b] = d[b], d[a]
This is what I've came up with, but I'm looking for a more simple and concise way. Is there any, as far as you know?
You can use a slightly more clever means of determining the keys to swap by doing:
a, b = d.keys() - {key} # On Py3; on Python 2.7, you'd use d.viewkeys()
but it's a pretty minor "improvement"; using set operations moves more work to the C layer, avoiding the Python layer iteration of a list comprehension, but the difference when you're talking about iterating three values is pretty trivial.
It's using a KeysView (a live, set-like view of the dict's keys) to get set operations to preserve the two keys not passed.
I'd do this this way, to avoid using loop:
def swap(dictS, key):
keys = list(dictS.keys())
keys.remove(key)
dictS[keys[0]], dict[keys[1]] = dictS[keys[1]], dict[keys[0]]
To solve this, we first need to find the two keys that are not same as the input key. We then just swap the values for those keys.
def swap(d, key):
keys_to_swap = []
for k in d:
if k != key:
keys_to_swap.append(k)
# keys_to_swap are the keys that need to be swapped
# Swap now
temp = d.get(keys_to_swap[0])
d[keys_to_swap[0]] = d.get(keys_to_swap[1])
d[keys_to_swap[1]] = temp
return d
Your original answer is correct, but you are not returning d.
So to correct your solution:
def swap2(d, key):
a, b = [_ for _ in d if _ != key]
d[a], d[b] = d[b], d[a]
return d #Added this line