intercept dictionary items which are two dimensional array - python

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.

Related

Merging nested lists alternatively [duplicate]

This question already has answers here:
Transpose list of lists
(14 answers)
Closed 9 months ago.
Input is [[159,159],[21,21]]
and I need
output like [[159,21],[159,21]]
I have searched python solution and tried a lot still am not getting solution, please share me solution.
Steps
zip the data together
convert the zipped tuple to list using map
convert the whole thing to be a list
Code
data = [[159,159],[21,21]]
print(list(map(list, zip(data[0],data[1]))))
Output
[[159,21],[159,21]]
You can use zip:
in_lists = [[159,159], [21,21]]
out_lists = list(zip(*in_lists))
print(out_lists)
which outputs
[(159, 21), (159, 21)]
The * in zip(*in_lists) will "unpack" the iterator in_lists and feed them to zip as separate arguments, which will be like zip([159, 159], [21, 21]). The zip function then combines the i-th element from all iterables into tuples, which results in [(159, 21), (159, 21)].
zip will do just that:
lst = [[159, 159], [21, 21]]
lst2 = list(zip(*lst))
print(lst2) # [(159, 21), (159, 21)]
if you need the nested elements to be lists as well:
lst2 = [list(item) for item in zip(*lst)] # [[159, 21], [159, 21]]

Is there a simpler way to find arithmetic sequences from three sets of numbers?

I have three sets of numbers, from which the goal is to find as many sets that form an arithmetic sequence as possible. I know that one set corresponds to the first number of each sequence, and so on. With these (shortened) versions of the lists, what would be a way to find the sequences? My only idea up until now was nested for loops, which worked for smaller lists but began to take too long with the full lists.
clist = [7, 11, 52, 102, 144, 314]
tlist = [10, 29, 79, 94, 121, 146]
flist = [13, 47, 184, 190, 544, 649]
Thanks in advance for any help
So first you want the empty set, every set of just one element, and every set of just two elements, since all of these are arguably an arithmetic series by technicality:
series = [[]]
for j in range(len(clist)):
series.append([clist[j]])
series.append([tlist[j]])
series.append([flist[j]])
for k in range(len(clist)):
series.append([clist[j],tlist[k]])
series.append([clist[j],flist[k]])
series.append([flist[j],tlist[k]])
series.append([flist[j],clist[k]])
series.append([tlist[j],clist[k]])
series.append([tlist[j],flist[k]])
if j != k:
series.append([tlist[j],tlist[k]])
series.append([clist[j],clist[k]])
series.append([flist[j],flist[k]])
I excluded the case where j = k because otherwise there are infinitely many solutions where each element is the same and the characteristic difference is 0 (e.g. [13], [13,13,13,13,13,13], [13,13,13,13,13,13,13,13,13,13] ...)
So "series" now includes every arithmetic sequence you can make from these lists of length 0, 1, or 2. The next step is to check the difference between each of the elements in every 2-length arithmetic sequence, and to write code that checks for a number being that difference more again. For example, the list [7, 10] has a difference of 3 so the next element that could make the list is "13". We can write code that first checks all the lists currently in series, then checks if there is a number in any of the lists which is the characteristic difference of the series more than the last element, and if there is, appends a new list (which is the old list plus the new element) to the list of series.
This question sounds vaguely homework-y so I won't do it for you, but hopefully my comment makes it clear what you should do.
An arithmetic sequence is fully described by two parameters, the initial value and a common difference. list1 is assumed to contain all initial values, list2 and list3 represents the candidates for the next terms in the sequence. Find the common difference between list1 and list2, then between list2 and list3. Check then if same common difference. If it the case the you have an arithmetic sequence.
list1 = [7, 11, 52, 102, 144, 314]
list2 = [10, 29, 79, 94, 121, 146]
list3 = [13, 47, 184, 190, 544, 649]
cd1 = [] # list of common differences between list1 and list2
for l1 in list1:
cd1 += [(l1, i2, i2 - l1) for i2 in list2]
cd2 = [] # list of common differences between list2 and list3
for l2 in list2:
cd2 += [(l2, i3, i3 - l2) for i3 in list3]
arithmetics_seqs = []
for d1 in cd1:
# check if same common differences between cd1 and cd2
arithmetics_seqs += [d1[:2]+(d2[1],) for d2 in cd2 if d2[-1] == d1[-1]]
print(arithmetics_seqs)
Output
[(7, 10, 13), (11, 29, 47), (52, 121, 190), (102, 146, 190)]

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])

Find gaps in list of range values

I found numerous similar questions in other programming languages (ruby, C++, JS, etc) but not for Python. Since Python has e.g. itertools I wonder whether we can do the same more elegantly in Python.
Let's say we have a "complete range", [1,100] and then a subset of ranges within/matching the "complete range":
[10,50]
[90,100]
How can we extract the not covered positions, in this case [1,9], [51,89]?
This is a toy example, in my real dataset I have ranges up to thousands.
Here is a neat solution using itertools.chain: I've assumed the input ranges don't overlap. If they do, they need to be simplified first using a union-of-ranges algorithm.
from itertools import chain
def range_gaps(a, b, ranges):
ranges = sorted(ranges)
flat = chain((a-1,), chain.from_iterable(ranges), (b+1,))
return [[x+1, y-1] for x, y in zip(flat, flat) if x+1 < y]
Taking range_gaps(1, 100, [[10, 50], [90, 100]]) as an example:
First sort the ranges in case they aren't already in order. If they are guaranteed to be in order, this step is not needed.
Then flat is an iterable which will give the sequence 0, 10, 50, 90, 100, 101.
Since flat is lazily evaluated and is consumed by iterating over it, zip(flat, flat) gives a sequence of pairs like (0, 10), (50, 90), (100, 101).
The ranges required are then like (1, 9), (51, 89) and the case of (100, 101) should give an empty range so it is discarded.
Assuming the list contains only integers, and the sub-ranges are in increasing order and not overlapping, You can use below code.
This code will take all sub ranges one by one, and will compare with original complete range and the sub range before it, to find the missing range.
[start,end]=[1,100]
chunks=[[25,31],[7,15],[74,83]]
print([r for r in [[start,chunks[0][0]-1] if start!=chunks[0][0] else []] + [[chunks[i-1][1]+1, chunks[i][0]-1] for i in range(1,len(chunks))]+[[chunks[-1][1]+1,end] if end!=chunks[-1][1] else []] if r])
Input
[1,100]
[[7,15],[25,31],[74,83]]
Output
[[1, 6], [16, 24], [32, 73], [84, 100]]
If increasing order of sub ranges are not guaranteed. you can include below line to sort chunks.
chunks.sort(key=lambda x: x[0])
This is a generic solution:
def gap(N, ranges):
ranges=[(min1, max1), (min2, (max2), ......, (minn, maxn)]
original=set(range(N))
for i in ranges:
original=original-set(range(i[0], i[1]))
return original

Randomly assign each of the coordinates [a,b] with each of the elements in a list

GRIDCOLS = 3;
GRIDROWS = 4 ;
gidder = 20;
gridxy = [];
for column in range (GRIDCOLS):
.. yrow = column * 100+ 50
.. for row in range (GRIDROWS):
.. xcell = row * 100+50
.. ycell = yrow + random.randint(-gidder, gidder)
.. gridxy.append([xcell, ycell])
.. print (gridxy)
this would create something like this [50, 58], [150, 56], [250, 39], [350, 52]
sumlist = ['a','b','c','$','4','2','3']
and what i want to do is assigning each of the coordinates [a,b] with each of the elements within the sumlist randomly.
I'm not really sure how to approach this. Do i do something with the index? Please help.
Thank you.
What kind of assignment do you need?
You can use zip([iterable, ...])
This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables.
>>> zip(sumlist, gridxy)
[('a', [50, 58]), ('b', [150, 56]), ('c', [250, 39]), ('$', [350, 52])]
You can create a dict:
>>> dict(zip(sumlist, gridxy))
{'a': [50, 58], 'b': [150, 56], 'c': [250, 39], '$': [350, 52]}
If you need a ordered dictionary you can use collections.OrderedDict
Return an instance of a dict subclass, supporting the usual dict methods.
You must random.shuffle your data...
import random
sumlist = ['a','b','c','$','4','2','3']
random.shuffle(sumlist) # shuffles in place!
At this point you have a random permutation of your data, stored into sumlist and you can proceed with pairing the sumlist and the gridxy elements, usually using the zip builtin (that truncates the pairing at the shortest iterable's length) or zip_longest in the itertools module that allow you to use a default value as a fill-in.
# create a list of tuples
lot = [t for t in zip(sumlist,gridxy)]
# create a dict
d = {s:xy for s, xy in zip(sumlist,gridxy)}
Of course you can use zip_longest if you feel appropriate to use default values in your code.
Pay attention to the fact that random.shuffle operates in place (and returns None), so that if you want to access your data in the original order, then you want to save it somewhere before shuffling
...
original_list = sumlist[:]
random.shuffle(sumlist)
...

Categories

Resources