update the value in set Python? - python

Here an example of my set, which I would like to update:
>>> x = set()
>>> x.add(('A1760ulorenaf0821x151031175821564', 1, 0))
>>> x
set([('A1760ulorenaf0821x151031175821564', 1, 0)])
My expected result would be:
set([('A1760ulorenaf0821x151031175821564', 1, 1)])
How I can do it? Is a set is the best option, or have I to use another data structure for that? I thought that update method in set can do that. However, I made mistake, and that is not a good solution as it does not consider the first parameter as a key and repeat the elements.

You'll have to remove the element from the set, and add a new element with that value updated. That's because sets use hashing to efficiently eliminate duplicates. If mutating the elements directly was allowed you'd break this model.
I think you only want the first element to be unique, and track some data associated with that first element. If so you want to use a dictionary instead; use the first element as a key to map to the other two values, in a list for easy altering:
>>> x = {}
>>> x['A1760ulorenaf0821x151031175821564'] = [1, 0]
>>> x['A1760ulorenaf0821x151031175821564'][1] += 1 # increment the second element.
>>> x
{'A1760ulorenaf0821x151031175821564': [1, 1]}
Keys in a dictionary also must be unique.
Note that set.update() only gives you a union operation; the set is updated in-place by adding all elements from the argument(s) that are not already in the set. set.update() cannot alter elements already in the set, because elements the set should not be altered (or at least not in ways that change their hash and equality).

You are better off using a dict if you are trying to have keys and values and you want to update based on key:
x = {'A1760ulorenaf0821x151031175821564' : [1, 0]}
x['A1760ulorenaf0821x151031175821564'] = [1, 1]

Related

.append() behaves differently for Python dictionaries initialized from two different methods

ky = ['a','b','c']
val = 15
dict_1 = dict.fromkeys(ky,[])
dict_1['a'].append(val)
dict_2 = {'a':[],'b':[],'c':[]}
dict_2['a'].append(val)
print(dict_1)
print(dict_2)
they are all using the same ref when you use dict.fromkeys() A change to one is a change to all since they are the same object
You could use a dict comprehension instead of append:
keys = ['a','b','c']
value = [0, 0]
{key: list(value) for key in keys}
{'a': [0, 0], 'b': [0, 0], 'c': [0, 0]}
Please correct me if I'm wrong, but given your post, I'm presuming your question is why dict_1 has the same value (15) for all its keys a, b, and c as the end result, right?
If so, I agree that this is unintuitive behavior at a first glance, but what is happening is that by passing [] (an empty list) as the second optional argument for the fromkeys method, you're populating dict_1 dictionary with references to the same single empty list, hence, when you append val to the key a, all other keys are updated with the same value as well (you passed the empty list as reference. see difference between passing by reference vs passing by value ).
As you noticed yourself, there are other ways to initialize a dictionary of empty lists in Python (as you did "manually" with dict_2).
In case you're interested in another "less manual" way to initialize a dictionary of empty lists in Python, you could use a list comprehension to do so, as in the following example:
dict_3 = {k : [] for k in ky}
That would initialize dict_3 with empty lists (passed by value), thus, keys b and c would be unaffected when you append val to the key a.
I hope that helps to clarify your example. Kind regards.
With dict_1 = dict.fromkeys(ky,[]), all keys are mapped to the same (empty) array.
So whenever you change the contents of that array, each one of these keys will (still) point to the same array containing these new contents.
dict_1 = dict.fromkeys(ky,[]) creates a single list and then calls fromkeys. That one list is used for the value paired with each key. One list referenced through all of the keys.
If you want unique lists, use a dictionary comprehension
dict_3 = {k:[] for k in ky}
Here, k:[] is evaluated for each key and a new list is created for each value.

How to know when to refer an item in a for loop by itself vs. referring to an item as an index of the list

In a for loop, I'm trying to understand when to refer to an item by its item name and when to refer to the item as an index of the list I'm looping through.
In the code pasted below, I don't understand why "idx" is referred to in the "if" statement with a reference to the list index but then in the definition of maximum_score_index, it is referred to by itself.
def linear_search(search_list):
maximum_score_index = None
for **idx** in range(len(search_list)):
if not maximum_score_index or **search_list[idx]** > search_list[maximum_score_index]:
maximum_score_index = **idx**
return maximum_score_index
I'd love to have an explanation so I can differentiate in the future and some examples to show the difference so I can understand.
In Python, range(num) (more or less) returns a list of numbers from 0 through num - 1. It follows that range(len(my_list)) will generate a list of numbers from 0 through the length of my_list minus one. This is frequently useful, because the generated numbers are the indices of each item in my_list (Python lists start counting at 0). For example, range(len(["a", "b", "c"])) is [0, 1, 2], the indices needed to access each item in the original list. ["a", "b", "c"][0] is "a", and so on.
In Python, the for x in mylist loop iterates through each item in mylist, setting x to the value of each item in order. One common pattern for Python for loops is the for x in range(len(my_list)). This is useful, because you loop through the indices of each list item instead of the values themselves. It's almost as easy to access the values (just use my_list[x]) but it's much easier to do things like access the preceding value (just use my_list[x-1], much simpler than it would be if you didn't have the index!).
In your example, idx is tracking the index of each list item as the program iterates through search_list. In order to retrieve values from search_list, the program uses search_list[idx], much like I used my_list[x] in my example. The code then assigns maximum_score_index to the index itself, a number like 0, 1, or 2, rather than the value. It's still easy to find out what the maximum score is, with search_list[maximum_score_index]. The reason idx is not being used as a list accessor in the second case is because the program is storing the index itself, not the value of the array at that index.
Basically, this line:
if not maximum_score_index or **search_list[idx]** > search_list[maximum_score_index]:
maximum_score_index = **idx**
Can be thought of as:
if (this is the first pass) or (element at index > this loop-iteration element):
keep this index as largest element
What I recommend to do:
Go through the code, on a piece of paper and iterate over a list to
see what the code does
Write the code in any IDE, and use a debugger
to see what the code does
Are you looking for the index of the highest element in the list or the value?
If you are looking for the value, it can be as simple as:
highest = max(search_list)
You could also use enumerate, which will grant you "free" access to the current index in the loop:
>>> search_list
[10, 15, 5, 3]
>>> maximum_score_index = None
>>> for idx, value in enumerate(search_list):
... if not maximum_score_index or search_list[idx] > value:
... maximum_score_index = idx
...
>>> maximum_score_index
1
>>> search_list[maximum_score_index]
15

How to find something in a 2D array when only looking for one item of the 2D array?

for example if I had
array=[["A",1],["B",2],["C",1]]
is there any way I can find ["A",1] by just looking for "A"? I'm trying to use this in a situation where the first thing in the array is unique so there's no point in looking at the second, also I have no way of knowing what the second variable is
Iterate over items present inside the outer list and check that the first element of inner list satisfies a particular condition.
>>> a=[["A",1],["B",2],["C",1]]
>>> next(i for i in a if i[0] == 'A')
['A', 1]
>>> [i for i in a if i[0] == 'A']
[['A', 1]]
If you're in control of the datatype, depending on whate else you're doing with this object, a dictionary may be a better choice for this:
Rather than
array=[["A",1],["B",2],["C",1]]
use
d={"A":1, "B":2, "C":1}
Then you can access the element associated with "A" simply with
>> d["A"]
1
If you want to transform your list into a dictionary:
d = dict(array)

python dictionary comprehension iterator

Hey I have a doubt in the following python code i wrote :
#create a list of elements
#use a dictionary to find out the frequency of each element
list = [1,2,6,3,4,5,1,1,3,2,2,5]
list.sort()
dict = {i: list.count(i) for i in list}
print(dict)
In the dictionary compression method, "for i in list" is the sequence supplied to the method right ? So it takes 1,2,3,4.. as the keys. My question is why doesn't it take 1 three times ? Because i've said "for i in list", doesn't it have to take each and every element in the list as a key ?
(I'm new to python so be easy on me !)
My question is why doesn't it take 1 three times ?
That's because dictionary keys are unique. If there is another entry found for the same key, the previous value for that key will be overwritten.
Well, for your issue, if you are only after counting the frequency of each element in your list, then you can use collections.Counter
And please don't use list as variable name. It's a built-in.
>>> lst = [1,2,6,3,4,5,1,1,3,2,2,5]
>>> from collections import Counter
>>> Counter(lst)
Counter({1: 3, 2: 3, 3: 2, 5: 2, 4: 1, 6: 1})
Yes, your suspicion is correct. 1 will come up 3 times during iteration. However, since dictionaries have unique keys, each time 1 comes up it will replace the previously generated key/value pair with the newly generated key/value pair. This will give the right answer, it's not the most efficient. You could convert the list to a set instead to avoid reprocessing duplicate keys:
dict = {i: list.count(i) for i in set(list)}
However, even this method is horribly inefficient because it does a full pass over the list for each value in the list, i.e. O(n²) total comparisons. You could do this in a single pass over the list, but you wouldn't use a dict comprehension:
xs = [1,2,6,3,4,5,1,1,3,2,2,5]
counts = {}
for x in xs:
counts[x] = counts.get(x, 0) + 1
The result for counts is: {1: 3, 2: 3, 3: 2, 4: 1, 5: 2, 6: 1}
Edit: I didn't realize there was something in the library to do this for you. You should use Rohit Jain's solution with collections.Counter instead.

What are the pythonic way to replace a specific set element?

I have a python set set([1, 2, 3]) and always want to replace the third element of the set with another value.
It can be done like below:
def change_last_elemnent(data):
result = []
for i,j in enumerate(list(data)):
if i == 2:
j = 'C'
result.append(j)
return set(result)
But is there any other pythonic way to do that,more smartly and making it more readable?
Thanks in advance.
Sets are unordered, so the 'third' element doesn't really mean anything. This will remove an arbitrary element.
If that is what you want to do, you can simply do:
data.pop()
data.add(new_value)
If you wish to remove an item from the set by value and replace it, you can do:
data.remove(value) #data.discard(value) if you don't care if the item exists.
data.add(new_value)
If you want to keep ordered data, use a list and do:
data[index] = new_value
To show that sets are not ordered:
>>> list({"dog", "cat", "elephant"})
['elephant', 'dog', 'cat']
>>> list({1, 2, 3})
[1, 2, 3]
You can see that it is only a coincidence of CPython's implementation that '3' is the third element of a list made from the set {1, 2, 3}.
Your example code is also deeply flawed in other ways. new_list doesn't exist. At no point is the old element removed from the list, and the act of looping through the list is entirely pointless. Obviously, none of that really matters as the whole concept is flawed.

Categories

Resources