My question might involve comprehension if I'm not mistaken.
So I have a dictionary as:
data = {
1: [2, 4],
2: [3],
3: [1, 2, 6],
4: [1, 3, 6],
6: [3, 4]
}
I wish to rearrange the dictionary values (not keys) such that with every occurrence of a "key" in any of the other values, the current key's values should now contain the "key" in who's value it originally occurred.
For example the dictionary should now look like this:
new_data = {
1: [3, 4],
2: [1, 3],
3: [2, 4, 6],
4: [1, 6],
6: [3, 4]
}
I know for sure that I must use another empty dictionary to solve this, and I must use looping. I have a starting point, but it's not efficient:
for pk,pv in zip(data.keys(), data.values()):
#print(pk,pv)
for pvs in pv:
#print(pvs)
if pk == pvs:
new_data.setdefault(pk, [])
new_data[pk].append(pvs)
print(new_data)
Any help is appreciated. Thanks in advance :)
(Using Ubuntu 14.04 32-Bit VM and Python 2.7)
Perhaps this is not the most efficient way to do this, but I would argue it's one of the nicest to read :).
One thing I should say before, if it's possible to change the initial dictionary values to set instead of list, that could result in some performance gains since set membership checks can be faster than listss.
Here goes:
def present_in(k, d):
return {idx for idx in d if k in d[idx]}
new_data = {k: present_in(k, data) for k in data}
Basically the present_in function creates a set of values corresponding to keys where k is present as a member. We simply then use this to create the new_data dictionary using a dictionary comprehension. Note again the values of this dictionary is a set, instead of a list. You can easily wrap them in list() if you do need lists.
EDIT:
If you would like new_data to have keys that may be missing as keys in data but present as one of the values, you can change the code to create a set of all possible keys first:
all_keys = {v for vs in data.values() for v in vs}
def present_in(k, d):
return {idx for idx in d if k in d[idx]}
new_data = {k: present_in(k, data) for k in all_keys}
{k:[i for i,j in data.items() if k in j] for k,_ in data.items()}
#Output:
#{1: [3, 4], 2: [1, 3], 3: [2, 4, 6], 4: [1, 6], 6: [3, 4]}
The below part essentially checks if the key(k from outer dict) is present in any of the values in dict, if present, it'll get the corresponding key into the list
[i for i,j in data.items() if k in j]
Related
Let's say I have a list of lists, for example:
[[0, 2], [0, 1], [2, 3], [4, 5, 7, 8], [6, 4]]
and if at least one of the values on a list is the same that another one of a different list, i would like to unite the lists so in the example the final result would be:
[[0, 1, 2, 3], [4, 5, 6, 7, 8]]
I really don't care about the order of the values inside the list [0, 1, 2, 3] or [0, 2, 1, 3].
I tried to do it but it doesn't work. So have you got any ideas? Thanks.
Edit(sorry for not posting the code that i tried before):
What i tried to do was the following:
for p in llista:
for q in p:
for k in llista:
if p==k:
llista.remove(k)
else:
for h in k:
if p!=k:
if q==h:
k.remove(h)
for t in k:
if t not in p:
p.append(t)
llista_final = [x for x in llista if x != []]
Where llista is the list of lists.
I have to admit this is a tricky problem. I'm really curious what does this problem represent and/or where did you find it out...
I initially have thought this is just a graph connected components problem, but I wanted to take a shortcut from creating an explicit representation of the graph, running bfs, etc...
The idea of the solution is this: for every sublist, check if it has some common element with any other sublist, and replace that with their union.
Not very pythonic, but here it is:
def merge(l):
l = list(map(tuple, l))
for i, h in enumerate(l):
sh = set(h)
for j, k in enumerate(l):
if i == j: continue
sk = set(k)
if sh & sk: # h and k have some element in common
l[j] = tuple(sh | sk)
return list(map(list, set(l)))
Here is a function that does what you want. I tried to use self-documenting variable names and comments to help you understand how this code works. As far as I can tell, the code is pythonic. I used sets to speed up and simplify some of the operations. The downside of that is that the items in your input list-of-lists must be hashable, but your example uses integers which works perfectly well.
def cliquesfromlistoflists(inputlistoflists):
"""Given a list of lists, return a new list of lists that unites
the old lists that have at least one element in common.
"""
listofdisjointsets = []
for inputlist in inputlistoflists:
# Update the list of disjoint sets using the current sublist
inputset = set(inputlist)
unionofsetsoverlappinginputset = inputset.copy()
listofdisjointsetsnotoverlappinginputset = []
for aset in listofdisjointsets:
# Unite set if overlaps the new input set, else just store it
if aset.isdisjoint(inputset):
listofdisjointsetsnotoverlappinginputset.append(aset)
else:
unionofsetsoverlappinginputset.update(aset)
listofdisjointsets = (listofdisjointsetsnotoverlappinginputset
+ [unionofsetsoverlappinginputset])
# Return the information in a list-of-lists format
return [list(aset) for aset in listofdisjointsets]
print(cliquesfromlistoflists([[0, 2], [0, 1], [2, 3], [4, 5, 7, 8], [6, 4]]))
# printout is [[0, 1, 2, 3], [4, 5, 6, 7, 8]]
This solution modifies the generic breadth-first search to gradually diminish the initial deque and update a result list with either a combination should a match be found or a list addition if no grouping is discovered:
from collections import deque
d = deque([[0,2] , [0,1] , [2,3] , [4,5,7,8] , [6,4]])
result = [d.popleft()]
while d:
v = d.popleft()
result = [list(set(i+v)) if any(c in i for c in v) else i for i in result] if any(any(c in i for c in v) for i in result) else result + [v]
Output:
[[0, 1, 2, 3], [8, 4, 5, 6, 7]]
I would like to apply this idea to separate a list of lists into individually named list. Say L = [[0,1,2],[3,4,5],[6,7,8]] and I want the first list ([0,1,2]) to be separate to give L0 = l[0] (first list within the list is labeled as L0). My ideas is this:
for i in range(11):
'l{}'.format(i) = l[i]
but the error message is this: can't assign to function call. I am hoping to accomplish this ultimately:
for i in range(11):
list( 'l{}'.format(i)) = l[i]
in order to convert the string into a list. Anyone know of an way to make this work or is the idea a bust?
The simplest way to do this is using tuple packing/unpacking
L = [[0,1,2],[3,4,5],[6,7,8]]
L0, L1, L2 = L
print(L0)
print(L1)
print(L2)
result:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
You can create variables dynamically (However I don't think its a good idea). Dynamically creating variables should not be used where a dict can be used instead. If you do not know how to create dynamic variables its probably means you shouldn't. there is more than enough info in the net to look up on a quick google search to know why.
That being said here is a way to do what you want using the dict method.
L = [[0,1,2],[3,4,5],[6,7,8]]
my_dict = {}
for x in range(len(L)):
my_dict[("L%s"%(x))] = L[x]
print (my_dict)
The result would be:
{'L0': [0, 1, 2], 'L1': [3, 4, 5], 'L2': [6, 7, 8]}
Then all you need to do is interact with the dict to get anything you need from those list.
You can use exec to execute a string as if it were Python code:
for i in range(len(L)):
exec('L{} = L[{}]'.format(i, i))
will give you variables L0, L1, L2 in your case.
L = [[0,1,2],[3,4,5],[6,7,8]]
myDict = {}
for index,inner_list in enumerate(L):
key = 'L'+str(index)
myDict[key]=inner_list
print(myDict)
RESULT
{'L0': [0, 1, 2], 'L1': [3, 4, 5], 'L2': [6, 7, 8]}
I'm kind of stumped here and would love some help.
So I have a dictionary like so
{'a':[1, 2, 3], 'b':[4, 5, 6]}
and I need to create a function which will automatically delete the first item in each list/key, so it should become
{'a':[2, 3], 'b':[5, 6]}
I know I should use the pop function, but it kind of gets confusing when there's way more than 2 keys and 3 values
You can use dictionary-comprehension for that:
>>> a = {'a':[1, 2, 3], 'b':[4, 5, 6]}
>>> {k: a[k][1:] for k in a}
{'a': [2, 3], 'b': [5, 6]}
Here's another solution,
dict1={'a':[1, 2, 3], 'b':[4, 5, 6]}
for item in dict1.values():
item.remove(item[0])
The for-loop moves through the values in the dictionary represented by 'dict1.values()'. The values are a set of lists, the '.remove()' function of the list removes the first occurrence of the element given, so if you give it the first element found in the list it would likewise remove it.
Hope this was useful!
You could achieve this with a one-liner using the map built-in function combined with a lambda function. Another advantage of this approach is that there's no copying involved (like in the slicing solution):
doc = {'a':[1, 2, 3], 'b':[4, 5, 6]}
map(lambda v: v.pop(0), doc.values())
This applies list.pop(0) on each value of your dict.
You can loop through the values of the dictionary and pop them one at a time. If you need further functionality or control, you can place it in a function.
dict_ = {'a':[1, 2, 3], 'b':[4, 5, 6]}
for val in dict_.values()
val.pop(0)
You can iterate through the dict & splice the list.
var1 = {'a':[1, 2, 3], 'b':[4, 5, 6]}
for element in var1:
var1[element] = var1[element][1:]
I have two lists of integers A and B, same length. List A is an unordered list integers, while list B is an ordered (in ascending order) list of integers with duplicates.
A and B are created such that pairwise no couples A[i],B[i] are identical.
My goal is the create a dictionary with key values taken from A, with values from B that pairwise match with A[i], i.e.,
myDict = {}
for i in A:
myDict[i] = []
for i in range(len(A)):
targetA = A[i]
targetB = B[i]
if targetA in myDict.keys():
myDict[targetA].append(targetB)
For very large datasets, this is taking an extremely long time. Is there another way to come up with the same dictionary in the end, possibly by exploiting the sorted structure of B?
You can use a defaultdict which should be simpler and faster:
from collections import defaultdict
A = [6, 6, 3, 2, 5, 2, 3]
B = [1, 2, 3, 3, 4, 6, 7]
purchase_dict = defaultdict(list)
for key, value in zip(A, B):
purchase_dict[key].append(value)
From the docs:
When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the default_factory function which returns an empty list. The list.append() operation then attaches the value to the new list. When keys are encountered again, the look-up proceeds normally (returning the list for that key) and the list.append() operation adds another value to the list. This technique is simpler and faster than an equivalent technique using dict.setdefault().
What you get:
>>> purchase_dict
defaultdict(<class 'list'>, {2: [3, 6], 3: [3, 7], 5: [4], 6: [1, 2]})
>>> purchase_dict[2]
[3, 6]
for example,
in this loop:
lst=[1,2,3,4,5,6,7,8,9]
for i in lst:
print i
Instead of just printing i, is there a way to asign i to a new variable each time?
so that I would get something like: item1=1 item2=2 item3=3 and so on.
Or is there a way to create new variables without knowing in advace how many I would need?
For example, a variable for each item in the list lst, or any other list (with any other len()) that the user gives.
for all of you who are wondering. the point of doing this is being able to call the variables later. my code searches for segments within a list that fit to a certein criteria, and I want to be able to reach the segments later, or at least for the user to be able to. I am new to programming, so if you have a better way to do that please tell me.
You want to partition the data according to a certain criteria. Let's say that you have a function figure_out_class that gives you a description for the class that you data falls on. Then you can use a dictionary to do this:
partitions = {}
for i in lst:
key = figure_out_class(i)
if key not in partitions:
partitions[key] = []
partitions[key].append(i)
This "is the key there already?" can be avoided populating the dictionary first using the classes you know you'll need, or using defaultdict:
from collections import defaultdict
partitions = defaultdict(list)
for i in lst:
key = figure_out_class(i)
partitions[key].append(i)
For a practical example, say that you want to classify numbers as odd or even:
def figure_out_class(number):
return ("odd" if number % 2 else "even")
Applying that function to the previous piece of code gives you:
>>> partitions['odd']
[1, 3, 5, 7, 9]
>>> partitions['even']
[2, 4, 6, 8]
Don't do this. You already have the data stored. Instead of doing item1, just do lst[0].
item2 -> lst[1]
item3 -> lst[2]
itemn -> lst[n-1]
Edit 2:
Try this:
>>> from itertools import groupby
>>> def split_condition(x):
return (x == 3)
>>> [list(g) for k, g in groupby([1, 2, 3, 4, 5, 6, 3, 4, 3, 5], split_condition)]
[[1, 2], [3], [4, 5, 6], [3], [4], [3], [5]]
You COULD do:
lst=[1,2,3,4,5,6,7,8,9]
for i in xrange(len(lst)):
exec('item%d=%d' % (i, lst[i]))
which will create variables item0, item1... all having values equal to respective positions in the list.
I don't see the point of all this though :)