Python seems to randomly invert list items during long loop - python

I have an array of dictionaries of the form:
[
{
generic_key: specific_key,
generic_value: specific_value
}
...
]
I am trying to interpret this into an array of dictionaries of this form:
[
{
specific_key: specific_value
}
...
]
I tried this:
new_array = []
for row in old_array:
values = list(row.values())
key = values[0]
val = values[1]
new_array.append({key: val})
This works in most cases, but in some, it swaps them around to form a dict like this:
{
specific_value: specific_key
}
I've looked at the source file, and the rows in which it does this are identical to the rows in which it does not do this.
It's perhaps worth mentioning that the list in question is about 3000 elements in length.
Am I doing something stupid? I guess that maybe list(row.values()) does not necessarily preserve the order, but I don't see why it wouldn't.
EDIT fixed code typo suggesting that it was appending sets

The order in which dict keys/values are enumerated is ostensibly arbitrary (there's certainly a logic to it, and as of I think python3.7+, it's consistent, but while I don't know off the top of my head what the ordering criteria are) - if you wanted order, you would have used a list instead of a dict to store them in the first place. If generic_key and generic_value are the same each time, then the ideal way to handle this problem is to simply extract by key:
key = row['generic_key']
value = row['generic_value']
If this isn't the case but there is a consistent way to differentiate between generic_key and generic_value, then you can grab both the keys and values, and do that:
items = tuple(row.items())
if items[0][0] is the generic_key: # insert whatever condition you need to here
key = items[0][1]
value = items[1][1]
else
key = items[1][1]
value = items[0][1]

Related

Function that makes dict from string but swaps keys and values?

I'm trying to make a function that takes in list of strings as an input like the one listed below:
def swap_values_dict(['Summons: Bahamut, Shiva, Chocomog',
'Enemies: Bahamut, Shiva, Cactaur'])
and creates a dictionary from them using the words after the colons as keys and the words before the colons as values. I need to clarify that, at this point, there are only two strings in the list. I plan to split the strings into sublists and, from there, try and assign them to a dictionary.
The output should look like
{'Bahamut': ['Summons','Enemies'],'Shiva':['Summons','Enemies'],'Chocomog':['Summons'],'Cactaur':['Enemies']}
As you can see, the words after the colon in the original list have become keys while the words before the colon (categories) have become the values. If one of the values appears in both lists, it is assigned two values in the final dictionary. I would like to be able to make similar dictionaries out of many lists of different sizes, not just ones that contain two strings. Could this be done without list comprehension and only for loops and if statements?
What I've Tried So Far
title_list = []
for i in range(len(mobs)):#counts amount of strings in list
titles = (mobs[i].split(":"))[0] #gets titles from list using split
title_list.append(titles)
title_list
this code returns ['Summons', 'Enemies'] which aren't the results I wanted to receive but I think they could help me write the function. I had planned on separating the keys and values into separate lists and then zipping them together afterwards as a dictionary.
Try:
def swap_values_dict(lst):
tmp = {}
for s in lst:
k, v = map(str.strip, s.split(":"))
tmp[k] = list(map(str.strip, v.split(",")))
out = {}
for k, v in tmp.items():
for i in v:
out.setdefault(i, []).append(k)
return out
print(
swap_values_dict(
[
"Summons: Bahamut, Shiva, Chocomog",
"Enemies: Bahamut, Shiva, Cactaur",
]
)
)
Prints:
{
"Bahamut": ["Summons", "Enemies"],
"Shiva": ["Summons", "Enemies"],
"Chocomog": ["Summons"],
"Cactaur": ["Enemies"],
}
I'd use a defaultdict. It saves you the trouble of manually checking if a key exists in your dictionary and constructing a new empty list, making for a rather concise function:
from collections import defaultdict
def swap_values_dict(mobs):
result = defaultdict(list)
for elem in mobs:
role, members = elem.split(': ')
for m in members.split(', '):
result[m].append(role)
return result

Python Comparing Values of Numpy Array Between 2 Dictionaries Value

I have 2 dictionary and an input
letter = 'd'
dict_1 = {"label_1": array(['a','b']), "label_2": array(['c','d']), ...}
dict_2 = {"label_1": array(['x','y']), "label_2": array(['z','o']), ...}
letter_translated = some_function(letter)
output desired: 'o'
What I have in mind right now is to get the index number from the array of the key "label_2" in dict_1 then searching for the same index in dict_2. I am open to other way of doing it. If you are unclear about the question, feel free to drop a comment.
Note: the arrays are numpy arrays
I propose to iterate through the first dictionary, while keeping a trace of how to get to the current element (key and i) so that we can look in the second dict in the same place:
from numpy import array
dict_1 = {"label_1": array(['a','b']), "label_2": array(['c','d'])}
dict_2 = {"label_1": array(['x','y']), "label_2": array(['z','o'])}
def look_for_corresponding(letter, d1, d2):
for key, array_of_letters in d1.items():
for position, d1_letter in enumerate(array_of_letters):
if d1_letter == letter:
return d2[key][position]
return None # Line not necessary, but added for clarity
output = look_for_corresponding('d', dict_1, dict_2)
print(output)
# o
Of course, this code will fail if dict_1 and dict_2 do not have exactly the same structure, or if the arrays are more than 1D. If those cases apply to you, please edit your question to indicate it.
Also, I am not sure what should be done if the letter is not to be found within dict_1. This code will return None, but it could also raise an exception.
What do you mean with 'index'? The number?
dictionaries don't have the concept of counted indices of their entries. You can only access data through the key (here "label_2"), or by iterating (for key in dict_1 ...).
The order is not guaranteed and can change. The order or your declaration is not kept.
If you wish to have "label_2" in both, then you need to access
key = "label_2"
item_from_1 = dict_1[key]
item_from_2 = dict_2[key]
If you need to iterate dict_1, then on each item find the appropriate item in the second, then this also needs to go over the key:
for (key,value1) in dict_1.iteritems():
value2 = dict_2[key]
.....
Note that the order the items come up in the loop may vary. Even from one run of the program to the next.

How to make a dictionary using two list but i want both two as a value And Key will be name and sys-id?

I have two values number and sys_id. I have made seperate list for both of the values. How can save it in any other data structure like dictionary, or something else because i those list of number and sys_id are related. I am doing it in Python
Below Is the code what i have done
ticket_num.append(resp['result'][idx]['number'])
sys_id.append(resp['result'][idx]['sys_id']) ```
This is making two list one for ticket_num and sys_id. As Ticket number and sys_id are related for example ticket_num = ['INC00012','INC00013','INC00014' ] ,
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
As this list are related like ticket_num[0] is directly link with sys_id[0]
So can i make a dictionary that contains ticket_num, sys_id directly without creating lists(for e.g. : {ticket_num : '...' , sys_id = '....' , ..... }
Use zip with dict
Ex:
ticket_num = ['INC00012','INC00013','INC00014' ]
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
print(dict(zip(ticket_num, sys_id)))
Output:
{'INC00012': '644323432sfasesdf213',
'INC00013': '644323432dfgdfkdskrwwr',
'INC00014': 'f283044423fdldsf09'}
Welcome to Stackoverflow.
Do you actually need the lists of ticket numbers and IDs? If not that you could instead consider building the structure you need instead of the lists.
You don't say whether you want to be able to look up IDs from ticket numbers or vice versa. This solution allows you to do either:
idx_from_ticket = {}
ticket_from_idx = {}
# In the loop that produces the values, instead of the current appends ...
temp = resp['result'][idx]
idx = temp['sys_id]
number = temp['number']
idx_from_ticket[number] = idx
ticket_from_idx[idx] = number
The two dictionaries can then be used to correlate the IDs and ticket numbers. If you want to actually do something else then I hope this code gives you enough clues.
If you do already have the lists and want to retain them then the zip function is your friend.
idx_from_ticket = dict(zip(ticket_num, sys_id))
ticket_from_idx = dict(zip(sys_id, ticket_num))
zip, when called with two argument, yields a sequence of two-element tuples, which the
dict function assumes are key/value pairs.

Python 2.7.9: list of dictionaries, calculating mean and std

Using Python 2.7.9: I have a list of dictionaries that hold a 'data' item, how do I access each item into a list so I may get the mean and standard deviation? Here's an example:
values = [{'colour': 'b.-', 'data': 12.3}, {'colour': 'b.-', 'data': 11.2}, {'colour': 'b.-', 'data': 9.21}]
So far I have:
val = []
for each in values:
val.append(each.items()[1][1])
print np.mean(val) # gives 10.903
print np.std(val) # gives 1.278
Crude and not very Pythonic(?)
Using list comprehension is probably easiest. You can extract the numbers like this:
numbers = [x['data'] for x in values]
Then you just call numpys mean/std/etc functions on that, just like you're doing.
Apologies for (perhaps) an unnecessary question, I've seen this:
average list of dictionaries in python
vals = [i['data'] for i in values]
np.mean(vals) # gives 10.903
np.std(vals) # gives 1.278
(Pythonic solution?)
It is an exceptionally bad idea to index into a dictionary since it has no guarantee of order. Sometimes the 'data' element could be first, sometimes it could be second. There is no way to know without checking.
When using a dictionary, you should almost always access elements by using the key. In dictionary notation, this is { key:value, ... } where each key is "unique". I can't remember the exact definition of "unique" for a python dictionary key, but it believe it is the (type, hash) pair of your object or literal.
Keeping this in mind, we have the more pythonic:
val = []
for data_dict in values:
val.append(data_dict['data'])
If you want to be fancy, you can use a list completion which is a fancy way of generating a list from a more complex statement.
val = [data_dict['data'] for data_dict in values]
To be even more fancy, you can add a few conditionals so check for errors.
val = [data_dict['data'] for data_dict in values if (data_dict and 'data' in data_dict)]
What this most-fancy way of doing thing is doing is filtering the results of the for data_dict in values iteration with if (data_dict and 'data' in data_dict) so that the only data_dict instances you use in data_dict['data'] are the ones that pass the if-check.
You want a pythonic one Liner?
data = [k['data'] for k in values]
print("Mean:\t"+ str(np.mean(data)) + "\nstd :\t" + str(np.std(data)))
you could use the one liner
print("Mean:\t"+ str(np.mean([k['data'] for k in values])) + "\nstd :\t" + str(np.std([k['data'] for k in values])))
but there really is no point, as both print
Mean: 10.9033333333
std : 1.27881021092
and the former is more readable.

Checking items in a list of dictionaries in python

I have a list of dictionaries=
a = [{"ID":1, "VALUE":2},{"ID":2, "VALUE":2},{"ID":3, "VALUE":4},...]
"ID" is a unique identifier for each dictionary. Considering the list is huge, what is the fastest way of checking if a dictionary with a certain "ID" is in the list, and if not append to it? And then update its "VALUE" ("VALUE" will be updated if the dict is already in list, otherwise a certain value will be written)
You'd not use a list. Use a dictionary instead, mapping ids to nested dictionaries:
a = {
1: {'VALUE': 2, 'foo': 'bar'},
42: {'VALUE': 45, 'spam': 'eggs'},
}
Note that you don't need to include the ID key in the nested dictionary; doing so would be redundant.
Now you can simply look up if a key exists:
if someid in a:
a[someid]['VALUE'] = newvalue
I did make the assumption that your ID keys are not necessarily sequential numbers. I also made the assumption you need to store other information besides VALUE; otherwise just a flat dictionary mapping ID to VALUE values would suffice.
A dictionary lets you look up values by key in O(1) time (constant time independent of the size of the dictionary). Lists let you look up elements in constant time too, but only if you know the index.
If you don't and have to scan through the list, you have a O(N) operation, where N is the number of elements. You need to look at each and every dictionary in your list to see if it matches ID, and if ID is not present, that means you have to search from start to finish. A dictionary will still tell you in O(1) time that the key is not there.
If you can, convert to a dictionary as the other answers suggest, but in case you you have reason* to not change the data structure storing your items, here's what you can do:
items = [{"ID":1, "VALUE":2}, {"ID":2, "VALUE":2}, {"ID":3, "VALUE":4}]
def set_value_by_id(id, value):
# Try to find the item, if it exists
for item in items:
if item["ID"] == id:
break
# Make and append the item if it doesn't exist
else: # Here, `else` means "if the loop terminated not via break"
item = {"ID": id}
items.append(id)
# In either case, set the value
item["VALUE"] = value
* Some valid reasons I can think of include preserving the order of items and allowing duplicate items with the same id. For ways to make dictionaries work with those requirements, you might want to take a look at OrderedDict and this answer about duplicate keys.
Convert your list into a dict and then checking for values is much more efficient.
d = dict((item['ID'], item['VALUE']) for item in a)
for new_key, new_value in new_items:
if new_key not in d:
d[new_key] = new_value
Also need to update on key found:
d = dict((item['ID'], item['VALUE']) for item in a)
for new_key, new_value in new_items:
d.setdefault(new_key, 0)
d[new_key] = new_value
Answering the question you asked, without changing the datastructure around, there's no real faster way of looking without a loop and checking every element and doing a dictionary lookup for each one - but you can push the loop down to the Python runtime instead of using Python's for loop.
I haven't tried if it ends up faster though.
a = [{"ID":1, "VALUE":2},{"ID":2, "VALUE":2},{"ID":3, "VALUE":4}]
id = 2
tmp = filter(lambda d: d['ID']==id, a)
# the filter will either return an empty list, or a list of one item.
if not tmp:
tmp = {"ID":id, "VALUE":"default"}
a.append(tmp)
else:
tmp = tmp[0]
# tmp is bound to the found/new dictionary

Categories