Combining two lists of objects based on an attribute - python

Every example of list or set usage in Python seems to include trivial cases of integers but I have two lists of objects where the name attribute defines whether two objects instances are "the same" or not (other attributes might have different values).
I can create a list that contains all items from both lists, sorted, with
tmpList = sorted(list1 + list2, key=attrgetter('name'))
but how do I do the same so that list items that have the same value in the name attribute are selected from the second list?
E.g combining these two lists
list1 = [obj('Harry',18), obj('Mary',27), obj('Tim', 7)]
list2 = [obj('Harry', 22), obj('Mary', 27), obj('Frank', 40)]
would result in
list = [obj('Harry',22), obj('Mary', 27), obj('Tim', 7), obj('Frank', 40)]
(I used obj() as a short-hand notation for an object that has two attributes.)
It seems like I can't use the attrgetter() function in most set and list functions like I can with the sorted() function so I can't figure out how I'm supposed to do this. I suspect I could use a lambda function, but I'm not too familiar with functional programming so I don't seem to manage to figure it out.
The naive solution (first pick all items that are unique in both lists and then combine that list with what is left of the second list) seems quite long-winded so there must be a simpler way in Python.

Sounds to me like you might be better off with a dict instead of a list, using the name as the key, and the rest of the object as value. Then you can simply dict1.update(dict2).
>>> dict1 = {"Harry": 18, "Mary": 27, "Tim": 7}
>>> dict2 = {"Harry": 22, "Mary": 27, "Frank": 40}
>>> dict1.update(dict2)
>>> dict1
{'Tim': 7, 'Harry': 22, 'Frank': 40, 'Mary': 27}

Yes. The easy way is a dictionary.
list1 = {"Harry": 18, "Mary": 27, "Tim": 7}
list2 = {"Harry": 22, "Mary": 27, "Frank": 40}
list1.update(list2)
list is now {'Harry':22, 'Mary': 27, 'Tim': 7, 'Frank': 40}
If your data is more than just a number, that's OK. You can put any kind of object as the value for a dictionary.
list1['Harry'] = (1,"weee",54.55)

You can implement de __eq__ attribute in your object. Based on that you can compare your objects with the == operator.

Related

Return keys sorted by value in dictionary of arrays

I am no expert in python, so this may be easily solvable and/or duplicate.
I have a dictionary of arrays like so:
mydict = {
"Anna": [10, 25, 6],
"Bob": [15, 21, 9],
"Carl": [17, 28, 3]
}
What would be the easiest way to return a list of keys sorted based on one of the values in the array?
Say I wanted to sort them based on the second value of the array (25, 21, 28) so as to get a list in this order ["Bob", "Anna", "Carl"]
My dictionary is tens of thousands, possibly millions, of entries, so efficiency is quite important.
Make a list of easily sortable data structures like (25, 'Anna'), sort that, then get rid of the superfluous value. As a one-liner:
[i[1] for i in sorted((v[1], k) for k, v in mydict.items())]
You could use the obvious key function:
sorted(mydict, key=lambda k: mydict[k][1])

removing initial items from nested lists

I have a script which imports data and I am storing these in nested lists.
I have one list which instructs how many elements from each sub-list are to be discarded.
How do I do this?
I know how to do it manually, but I want to be able to upload a csv file into my program, and then let it run.
I have run the same line of data twice in csv file to try and make it simpler for me to fix, so I have
starting_index = [203,203]
but in principle this could have a 100 or so elements of different number.
I then have a whole series of nested lists. The number of elements in my starting_index matches the number of sub-lists within each list so at the moment there are only two sub-lists in each nested list.
I wanted to define a function that I could call on to pare each list. I know what is wrong with my code, but I do not know how to make it work.
def index_filter(original_list, new_list):
for i in starting_index:
print(i)
for index, value in enumerate(original_list):
for item,element in enumerate(value):
if item >= i:
new_list[index].append(element)
I realise now that this does not work, and the problems is the
for i in starting_index:
because when it finishes the first element in starting index, it then goes on to the next and appends more data. It doesn't error, but it does not do what I wanted it to do. I just want to remove in this case the first 203 elements from sub-list 1, and the first 203 elements from sub list two, but in principle those numbers will change.
I try and use enumerate all the time, and perhaps it's not appropriate here.
How can I solve this?
Thanks
Edit: Some sample data:
starting_index = [2,1,3]
list_one = [[15,34,67,89,44], [44,23,67,88,45,67,233,567,41,56.4],[45,6734,5,67,29,55,6345,23,89,45,6,8,3,4,5,876]]
ideal result:
list_one = [[67,89,44],[23,67,23,67,88,45,67,233,567,41,56.4],[67,29,55,6345,23,89,45,6,8,3,4,5,876]]
I have just come across the del statement which I am looking at, and I'll also have a look at the slice suggestion. Thanks
Edit: I tried the solution but I can't get it to work.
I tried that but when I put some test data in I get back the original unaltered list.
How do I access the output?
My test script:
original_list=[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38]]
starting_index=[3,6]
def index_filter(original_list, starting_index):
return [value[i:] for i, value in zip(starting_index, original_list)]
index_filter(original_list, starting_index)
print(index_filter)
print(original_list)
Outputs a strange message and the original unaltered list
<function index_filter at 0x039CC468>
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]]
Thank you
You need to loop through the starting_index and original_list in parallel, so use zip().
And you can use the slice value[i:] to get the part of a list starting at an index, rather than looping.
def index_filter(original_list, starting_index):
return [value[i:] for i, value in zip(starting_index, original_list)]
original_list=[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38]]
starting_index=[3,6]
new_list = index_filter(original_list, starting_index)
print(new_list)

intercept dictionary items which are two dimensional array

Here is my dictionary of n items.
{
"proceed": [[6,46] , [7,67], [12,217], [67,562], [67,89]],
"concluded": [[6,46] , [783,123], [121,521], [67,12351], [67,12351]],
...
}
imagine a dictionary s.t. like that with n keys and items which are two dimensional arrays.
I want to intercept all of them and take the result as [6,46]
I tried s.t. like that :
result=set.intersection(*map(set,output.values()))
however it got error because of items are two dimensinal array.
Can someone please help me how to do that ?
Thanks.
So... sets don't work for lists because lists are not hashable. Instead you'll have to make them sets of tuples like so:
result = set.intersection(*({tuple(p) for p in v} for v in output.values()))
Edit: works in py version >= 2.7
Completely agree with answer of #FHTMitchell but here's a bit of more explanation with example of why you can't get unique set with list and get TypeError: unhashable type
Consider below values:
x = {'concluded': [[6, 46], [783, 123], [121, 521], [67, 12351], [67, 12351]],
'proceed': [[6, 46], [7, 1], [12, 217], [67, 562], [67, 89]]}
y = {'concluded': ((6, 46), (67, 12351), (121, 521), (783, 123)),
'proceed': ((6, 46), (7, 1), (12, 217), (67, 89), (67, 562))}
x is the dictionary containing list of list as values; the main thing to note is that value of keys are stored as list which is mutable; but in y it's tuple of tuples or you may keep it as set which is not mutable
Now consider some how you managed to get your desire output [6,46] but if you notice it's a list contains some elements stored in a list so if you change the values as below:
x['proceed'][0][0] = 9
it will change your value [6, 46] to [9,46] in concluded key and now your output may or may not change which depends on how you iterated and stored it.

Adding a element in dictionary which consist of dictionaries.

I have a dictionary which consist of lists. Now how will it be possible to add a variable/element in the list for the example provided below.
inventory = {
'gold': 20,
'bag': ['chocolate', 'chips', 'food']
}
Now how do I add something in the list bag.
I have already tried this but it does not work.
inventory.bag.append('test')
inventory.bag.insert('test')
You need to use subscription, so object[...], to address elements in the dictionary:
inventory['bag'].append('test')
Here inventory['bag'] retrieves the value associated with the 'bag' key. This is a list object, so you can then call the append() method on that result.
You need access dict value like inventory['bag'], then because the value is a list, you just need call append method
inventory['bag'].append('test')
Demo of How to Append and Insert element in the list.
List append() method will add given element at the last.
>>> l1 = [11, 12, 13]
>>> l1.append(20)
>>> l1
[11, 12, 13, 20]
# ^
List insert() method will take two arguments, First is index where you want to insert given element and second is element which need to insert.
>>> l1.insert(1, 22)
>>> l1
[11, 22, 12, 13, 20]
# ^
Consider dictionary where key i.e.number have value as List Object.
>>> d = {"number":[11, 12]}
>>> d["number"]
[11, 12]
>>> d["number"].append(22)
>>> d
{'number': [11, 12, 22]}
>>> d["number"].insert(2, 20)
>>> d["number"]
[11, 12, 20, 22]
>>>

iterating dictionary and fetching values from inner dictionaries

am trying to build a logic which am not quit sure how to do with python. I have the following dictionary
{datetime.datetime(2011, 7, 18, 13, 59, 25): (u'hello-world', u'hello world'), datetime.datetime(2011, 7, 17, 15, 45, 54): (u'mazban-archeticture', u'mazban arch'), datetime.datetime(2011, 7, 7, 15, 51, 49): (u'blog-post-1', u'blog post 1'), datetime.datetime(2011, 7, 8, 15, 54, 5): (u'blog-post-2', u'blog post 2'), datetime.datetime(2011, 7, 18, 15, 55, 32): (u'blog-post-3', u'blog post 3')}
I want to iterate through the dictionary, find out if the date is equal today's date and then use the inner dictionary to build a url using the first value as a slug. Am able to iterate but I don't know how to fetch the inner value
# will only print dates
for i in dic:
print i
In python when you use 'for x in dic' it is the same as to use 'for x in dic.keys()' - you are iterating trough only keys not (key,value) pairs.
To do what you want you can take a look at the items() and iteritems() dictionary methods, they allows you to get access to (key,value) pairs:
for key,value in dic.iteritems():
if key == datetime.today(): # or (datetime.today() - key).seconds == <any value you expect>
# since value is a tuple(not a dict) and you want to get the first item you can use index 0
slug = value[0]
Read more about dictionaries and supported methods
If you want to access the value then you subscript the dictionary, unless you actually want tuples this is usually less hassle than using either .items() or .iteritems() methods:
for i in dic:
print i, dic[i]
BTW, you say 'inner dictionary' but you only have one dictionary, the values are tuples.

Categories

Resources