How to find some specific element in a set? - python

Given some set of tuples (x,y):
set([(1,2),(3,4),(3,2),(1,4)])
How do I find each tuple with the property (1,z) in the set?
In this example the edges (1,2),(1,4).
EDIT: Is there some other data structure that would support such a request?

Use a comprehension (set or list):
In [145]: st = set([(1,2),(3,4),(3,2),(1,4)])
In [146]: [(i, j) for i, j in st if i == 1]
Out[146]: [(1, 2), (1, 4)]
In [147]: {(i, j) for i, j in st if i == 1}
Out[147]: {(1, 2), (1, 4)}
Or if you don't want the result in a container, i.e. you just want to loop over the results, etc. you can use a function approach by using the built-in filter function:
result = filter(lambda x: x[0] == 1, st)

Related

Remove a tuple from a list if the tuple contains a certain element by given index

I have a list of tuples (num, id):
l = [(1000, 1), (2000, 2), (5000, 3)]
The second element of each tuple contains the identifier. Say that I want to remove the tuple with the id of 2, how do I do that?
I.e. I want the new list to be: l = [(1000,1), (5000, 3)]
I have tried l.remove(2) but it won't work.
You can use a list comprehension with a filter to achieve this.
l = [(1000, 1), (2000, 2), (5000, 3)]
m = [(val, key) for (val, key) in l if key != 2]
Or using filter:
l = [(1000, 1), (2000, 2), (5000, 3)]
print(list(filter(lambda x: x[1] != 2, l)))
output:
[(1000, 1), (5000, 3)]
That's because the value 2 is not in the list. Instead, something like the below: form a list of the second elements in your tuples, then remove the element at that position.
del_pos = [x[1] for x in l].index(2)
l.pop(del_pos)
Note that this removes only the first such element. If your instance is not unique, then use one of the other solutions. I believe that this is faster, but handles only the single-appearance case.
Simple list comprehension:
[x for x in l if x[1] != 2]
You may do it with:
>>> l = [(1000, 1), (2000, 2), (5000, 3)]
>>> for i in list(l):
... if i[1] == 2:
... l.remove(i)
In case you want to remove only first occurence, add break below remove line
One more possible solution
r = [(1000, 1), (2000, 2), (5000, 3)]
t = [i for i in r if i.count(2) == 0]

How to sum up a list of tuples having the same first element?

I have a list of tuples, for example:
(1,3)
(1,2)
(1,7)
(2,4)
(2,10)
(3,8)
I need to be able to sum up the second values based upon what the first value is, getting this result for the example list:
(1,12)
(2,14)
(3,8)
This question is very similar in nature to this one, however, my solution may not use any imports or for loops, and all answers to that question use one or the other. It's supposed to rely on list and set comprehension.
my_set = {x[0] for x in my_tuples}
my_sums = [(i,sum(x[1] for x in my_tuples if x[0] == i)) for i in my_set]
I guess. ... those requirements are not very good for this problem (this solution will be slow ...)
If you can use dictionaries the following should work
x = [(1,3), (1, 2), (1, 7), (2, 4), (2, 10), (3, 8)]
d = {}
[d.__setitem__(first, d.get(first, 0) + second) for first, second in x]
print(list(d.items()))
If you are using python2, you can use map to behave like izip_longest and get the index of where the groups end:
def sums(l):
st = set()
inds = [st.add(a) or ind for ind, (a, b) in enumerate(l) if a not in st]
return [(l[i][0], sum(sub[1] for sub in l[i:j])) for i, j in map(None, inds, inds[1:])]
Output:
In [10]: print(sums(l))
[(1, 12), (2, 14), (3, 8)]
for python 2 or 3 you can just use enumerate and check the index:
def sums(l):
st = set()
inds = [st.add(a) or ind for ind, (a, b) in enumerate(l) if a not in st]
return [(l[j][0], sum(sub[1] for sub in (l[j:inds[i]] if i < len(inds) else l[inds[-1]:])))
for i, j in enumerate(inds, 1)]
same output:
In [12]: print(sums(l))
[(1, 12), (2, 14), (3, 8)]
This is pretty straightforward, but it's definitely O(n**2), so keep your input data small:
data = (
(1,3),
(1,2),
(1,7),
(2,4),
(2,10),
(3,8),
)
d = { k:v for k,v in data }
d2 = [(t1,sum( v for k,v in data if k == t1 )) for t1 in d.keys() ]
print(d2)
Output is
[(1, 12), (2, 14), (3, 8)]
I'd use a defaultdict
from collections import defaultdict
x = [(1,3), (1, 2), (1, 7), (2, 4), (2, 10), (3, 8)]
d = defaultdict(int)
for k, v in x:
d[k] += v
print(list(d.items()))
if you need a one-liner (lambda inline function) using itertools
from itertools import groupby
myfunc = lambda tu : [(k, sum(v2[1] for v2 in v)) for k, v in groupby(tu, lambda x: x[0])])
print(myfunc(x))

Algorithm to extract edge list efficiently from a vector

I have a long list (~10 million elements) and the elements that have repeated values are pairs. I want to extract the list of pairs from the list, e.g.
R = [1,3,1,6,9,6,1,2,3,0]
will spit out list of pairs
P = [[e1,e3],[e1,e7],[e3,e7],[e4,e6],[e2,e9]]
What is the efficient algorithm to achieve this for a long list?
Group the indices together based on value, then iterate through pairs of indices using combinations.
from collections import defaultdict
from itertools import combinations
R = [1,3,1,6,9,6,1,2,3,0]
d = defaultdict(list)
for idx,item in enumerate(R,1):
d[item].append(idx)
result = []
for indices in d.itervalues():
result.extend(combinations(indices, 2))
print result
Result:
[(1, 3), (1, 7), (3, 7), (2, 9), (4, 6)]
Populating the defaultdict takes O(len(R)) time on average. Finding combinations is O(N!) time, where N is the number of indices in the largest group.
My simple solution:
def extract(edges):
dic = {}
for i in range(len(edges)):
if edges[i] in dic.keys():
dic[edges[i]].append(i+1)
else:
dic[edges[i]] = [i+1]
res = []
for k in sorted(dic.keys()):
res += combinations(dic[k])
return res
def combinations(positions):
ret = []
print positions
for i in range(len(positions)):
for j in range(i+1, len(positions)):
ret.append(["e"+str(positions[i]), "e"+str(positions[j])])
print ret
return ret
R = [1,3,1,6,9,6,1,2,3,0]
res = extract(R)
print res
As we can't see your input, you might encounter problems if there are many combinations. One thing to try is pypy, which sometimes gives me a (free) speed up.
Unless I understood it the wrong way, the simplest and optimal way to do this is to use a dictionary of already encountered values.
elem_dict = {}
output = []
for i, elem in zip (range (length(R))),R):
if elem_dict.has_key (elem):
output += [[duplicate, i] for duplicate in elem_dict[elem]]
else
elem_dict[elem] = set ()
elem_dict[elem].add (i)
print output #[[0, 2], [3, 5], [0, 6], [2, 6], [1, 8]]
Should be O(n log (n)) in average case, if I'm not mistaken, unless you have a lot of similar values in which case your output is O(n^2) anyway.
My approach would be to do a pass over the list to find the elements with the same value and store them into new lists, then find the elements that appear more than once and collect the combinations:
In [18]: from collections import defaultdict
In [19]: d = defaultdict(list)
In [20]: for i, e in enumerate(R, 1):
....: d[e].append(i)
....:
In [21]: from itertools import combinations
In [22]: from itertools import chain
In [23]: list(chain(*[list(combinations(v,2)) for v in d.values() if len(v) > 1]))
Out[23]: [(1, 3), (1, 7), (3, 7), (2, 9), (4, 6)]

compare to lists and return the different indices and elements in python

I want to compare to lists and return the different indices and elements.
So I write the following code:
l1 = [1,1,1,1,1]
l2 = [1,2,1,1,3]
ind = []
diff = []
for i in range(len(l1)):
if l1[i] != l2[i]:
ind.append(i)
diff.append([l1[i], l2[i]])
print ind
print diff
# output:
# [1, 4]
# [[1, 2], [1, 3]]
The code works, but are there any better ways to do that?
Update the Question:
I want to ask for another solutions, for example with the iterator, or ternary expression like [a,b](expression) (Not the easiest way like what I did. I want to exclude it.) Thanks very much for the patient! :)
You could use a list comprehension to output all the information in a single list.
>>> [[idx, (i,j)] for idx, (i,j) in enumerate(zip(l1, l2)) if i != j]
[[1, (1, 2)], [4, (1, 3)]]
This will produce a list where each element is: [index, (first value, second value)] so all the information regarding a single difference is together.
An alternative way is the following
>>> l1 = [1,1,1,1,1]
>>> l2 = [1,2,1,1,3]
>>> z = zip(l1,l2)
>>> ind = [i for i, x in enumerate(z) if x[0] != x[1]]
>>> ind
[1, 4]
>>> diff = [z[i] for i in ind]
>>> diff
[(1, 2), (1, 3)]
In Python3 you have to add a call to list around zip.
You can try functional style:
res = filter(lambda (idx, x): x[0] != x[1], enumerate(zip(l1, l2)))
# [(1, (1, 2)), (4, (1, 3))]
to unzip res you can use:
zip(*res)
# [(1, 4), ((1, 2), (1, 3))]

Find all occurences of an element in a matrix in Python

I have a list of lists and I want to find the cordinates of all occurences. I managed to do it, but I wonder if there is a better way to do it using numpy where for example.
This is what I did:
my_list = [[1,2,3,1, 3], [1,3,2]]
target_value = 3
locations = []
for k in range(len(my_list)):
indices = [i for i, x in enumerate(my_list[k]) if x == target_value]
locations.append((k, indices))
locations2 = []
for row in locations:
for i in row[1]:
locations2.append((row[0], i))
print locations2 # prints [(0, 2), (0, 4), (1, 1)]
While you could get this to work in numpy, numpy isn't all that happy with ragged arrays. I think the pure python comprehension version looks okay:
>>> my_list = [[1,2,3,1, 3], [1,3,2]]
>>> [(i,j) for i,x in enumerate(my_list) for j,y in enumerate(x) if y == 3]
[(0, 2), (0, 4), (1, 1)]

Categories

Resources