Detect ranges of integers in a list in python - python-3.x

I am trying to write a function "detect_range" which detects ranges of integers from a list let's say:
a = [2, 4, 5, 6, 7, 8, 10, 12, 13]
import itertools
def detect_range(L):
for i, j in itertools.groupby(enumerate(L), lambda x: x[1] - x[0]):
j = list(j)
yield j[0][1], j[-1][1]
print(list(detect_range(a)))
It prints:
[(2, 2), (4, 8), (10, 10), (12, 13)]
However, I do not want the single integer like 2 and 10 to be printed in a pair, but single. So the output which I am looking from this code is:
[2, (4, 9), 10, (12, 14)]

If you insist on using itertools, you should add an if-statement to differenciate between the different cases.
To make the code more readable, I added the temporal variables start and length.
import itertools
def detect_range(L):
for i, j in itertools.groupby(enumerate(L), lambda x: x[1] - x[0]):
j = list(j)
start = j[0][1]
length = len(j)
if length == 1:
yield start
else:
yield (start, start+length)
print(list(detect_range(a)))
[2, (4, 9), 10, (12, 14)]
Otherwise, you could scrap itertools and simply implement your own algorithm:
def detect_range(input_list):
start = None
length = 0
for elem in input_list:
# First element
if start is None:
start = elem
length = 1
continue
# Element in row, just count up
if elem == start + length:
length += 1
continue
# Otherwise, yield
if length == 1:
yield start
else:
yield (start, start+length)
start = elem
length = 1
if length == 1:
yield start
else:
yield (start, start+length)
print(list(detect_range(a)))
[2, (4, 9), 10, (12, 14)]

Change it to
if j[0][1] == j[-1][1]:
yield j[0][1]
else:
yield j[0][1], j[-1][1]

You can change the yield statement to have a condition -
def detect_range(L):
for i, j in itertools.groupby(enumerate(L), lambda x: x[1] - x[0]):
j = list(j)
yield (j[0][1], j[-1][1]) if j[0][1]!=j[-1][1] else j[0][1]
Output:
[2, (4, 8), 10, (12, 13)]
Also the expected output is different from the given output (apart from single 2 and 10). So, this code assumes that it was a typo

Related

How to find indices and combinations that adds upto given sum?

How to find the combinations and corresponding indices that adds upto given sum ?
And also, can it be handled list of elements of size 500000 (higher size) ?
Input:
l1 = [9,1, 2, 7, 6, 1, 5]
target = 8
**Constraints**
1<=(len(l1))<=500000
1<=each_list_element<=1000
Output:
Format : {index:element}
{1:1, 5:1, 4:6} #Indices : 1,5,4 Elements : 1,1,6
{1:1, 2:2, 6:5}
{5:1, 2:2, 6:5}
{1:1, 3:7}
{5:1, 3:7}
{2:2, 4:6}
Tried:
from itertools import combinations
def test(l1, target):
l2 = []
l3 = []
if len(l1) > 0:
for r in range(0,len(l1)+1):
l2 += list(combinations(l1, r))
for i in l2:
if sum(i) == target:
l3.append(i)
return l3
l1 = [9,1, 2, 7, 6, 1, 5]
target = 8
print(test(l1,target))
[(1, 7), (2, 6), (7, 1), (1, 2, 5), (1, 6, 1), (2, 1, 5)]
Can someone guide me ?
UPDATE
Apart from above, code fails to handle these scenarios
Input = [4,6,8,5,3]
target = 3
Outputs {} , need to output {4:3}
Input = [4,6,8,3,5,3]
target = 3
Outputs {} , need to output {5:3,3:3} #corrected index
Input = [1,2,3,15]
target = 15
Outputs = {}, need to output {3:15}
Your code was close, i would use enumerate to get the index and value as tuple pairs. I am always dropping any of the index and value tuples where that value is greater than the target since that cannot possible be a match. this will generate less combinations. Then like you i just iterate through the permutations of tuples and sum the values in each permutation, if it sums to the target then yield that permutation. lastly in the loop to output the values i give the perm to dict to convert into the dict format you wanted
from itertools import combinations
def find_sum_with_index(l1, target):
index_vals = [iv for iv in enumerate(l1) if iv[1] < target]
for r in range(1, len(index_vals) + 1):
for perm in combinations(index_vals, r):
if sum([p[1] for p in perm]) == target:
yield perm
l1 = [9, 1, 2, 7, 6, 1, 5]
target = 8
for match in find_sum_with_index(l1, target):
print(dict(match))
OUTPUT
{1: 1, 3: 7}
{2: 2, 4: 6}
{3: 7, 5: 1}
{1: 1, 2: 2, 6: 5}
{1: 1, 4: 6, 5: 1}
{2: 2, 5: 1, 6: 5}
You can just use index function to get index and store them as key:value pair with help of dictionary in another list such as following,
from itertools import combinations
def test(l1, target):
l2 = []
l3 = []
l4=[]
dict1={}
a=0
if len(l1) > 0:
for r in range(0,len(l1)+1):
l2 += list(combinations(l1, r))
for i in l2:
dict1={}
if sum(i) == target:
for j in i:
a=l1.index(j)
dict1[a]=j
l4.append(dict1)
l3.append(i)
return l4
l1 = [4,6,8,5,3]
target = 3
print(test(l1,target))
output:
[{4: 3}]
as you can see the condition l1 = [4,6,8,5,3] target = 3 works which is previously not working.
Hope this helps!

Get different sets of numbers with repetition

I have a list of numbers:
lst = [1, 2, 3, 1,4]
def permutation(lst):
# If lst is empty then there are no permutations
if len(lst) == 0:
return []
# If there is only one element in lst then, only
# one permuatation is possible
if len(lst) == 1:
return [lst]
# Find the permutations for lst if there are
# more than 1 characters
l = [] # empty list that will store current permutation
# Iterate the input(lst) and calculate the permutation
for i in range(len(lst)):
m = lst[i]
# Extract lst[i] or m from the list. remLst is
# remaining list
remLst = lst[:i] + lst[i + 1:]
# Generating all permutations where m is first
# element
for p in permutation(remLst):
l.append([m] + p)
return l
if __name__ == "__main__":
lst = [1, 2, 3, 1,4]
v_out = permutation(lst)
print(v_out)
I am only getting permutations of 4 length, I want permutatins of all lengths, and only distinct permutations. But within each permutation, repetition is allowed.
This should work... Using the permutations function from itertools and making a set out of everything to prevent duplicates from being added to the overall result
In [20]: from itertools import permutations
In [21]: a = [1, 1, 2, 3]
In [22]: all_results = set()
In [23]: for i in range(1, len(a)):
...: all_results.update(set(permutations(a, i)))
...:
In [24]: all_results
Out[24]:
{(1,),
(1, 1),
(1, 1, 2),
(1, 1, 3),
(1, 2),
(1, 2, 1),
(1, 2, 3),
(1, 3),
(1, 3, 1),
(1, 3, 2),
(2,),
(2, 1),
(2, 1, 1),
(2, 1, 3),
(2, 3),
(2, 3, 1),
(3,),
(3, 1),
(3, 1, 1),
(3, 1, 2),
(3, 2),
(3, 2, 1)}
In [25]:

Summation riddle duplicate values seen

a list the output we get repeated values (3,20,7)
how to remove the repeated values?
is there a easier way to solve this?
def riddle(x):
list=[]
i=0
for i in range(0,len(x)):
for j in range(i,len(x)):
for k in range(j,len(x)):
if ((x[i]+x[j]+x[k]) ==30) and x[i]!=x[j]!=x[k]:
list.append((x[i],x[j],x[k]))
i = i+1
j= j+1
k = k+1
return(list)
print(riddle(x))
x= [2,3,5,8,6,89,20,15,7]
def riddle(x):
ls = []
for i in range(len(x)):
for j in range(i+1,len(x)):
for k in range(j+1,len(x)):
u = x[i]+x[j]+x[k]
if u==30:
ls.append([x[i],x[j],x[k]])
return ls
x = [2,3,5,8,6,89,20,15,7]
riddle(x)
Out[58]: [[2, 8, 20], [3, 20, 7], [8, 15, 7]]
First of all, don't use the name 'list' for a list as it's a keyword. I am going with list1 instead.
To get your answer, replace return(list1) with return(set(list1)) to remove duplicates. If you want the answer as a list and not a set, do return(list(set(list1)))
(This will not be possible unless u rename your list to list1)
Code:
def riddle(x):
list1=[]
i=0
for i in range(0,len(x)):
for j in range(i,len(x)):
for k in range(j,len(x)):
if ((x[i]+x[j]+x[k]) ==30) and x[i]!=x[j]!=x[k]:
list1.append((x[i],x[j],x[k]))
i = i+1
j= j+1
k = k+1
return(list(set(list1)))
x= [2,3,5,8,6,89,20,15,7]
print(riddle(x))
Output
[(2, 8, 20), (8, 15, 7), (3, 20, 7)]

Finding unique combinations of tuples

Input: 1 2 3 4
Output: (1,2)(3,4)
(1,3)(2,4)
(1,4)(2,3)
I have been able to come up with a solution for the problem but it is efficient. It needs to be optimized.
comb = combinations(Arr,int(n/2))
l = []
for i in comb:
l.append(i)
final_comb = combinations(l,int(n/2))
for i in final_comb:
if is_unique(n,i):
print(i)
def is_unique(n,tup):
k = []
for i in tup:
for j in i:
k.append(j)
if len(set(k)) == n:
return True
return False
The output must be combinations of tuples such that they all have the numbers given as input
Use itertools
from itertools import combinations
list(combinations([1, 2, 3, 4], 2))
>>> [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

python: how to check elements in a string are extracted from another string and the occurrence are in order? [duplicate]

I want to test if an ordered set is a subset of a bigger ordered set. I used tuples and itertools.combinations:
def subset_test(a, b):
return a in itertools.combinations(b, len(a))
For instance,
>>> subset_test((0, 1, 2), (0, 3, 1, 4, 2))
True
>>> subset_test((0, 1, 2), (0, 3, 2, 4, 1))
False
It works, but is slow when I test big tuples.
You can simply use an iterator to keep track of the position in B
>>> A = (0, 1, 2)
>>> B = (0, 3, 1, 4, 2)
>>> b_iter = iter(B)
>>> all(a in b_iter for a in A)
True
Simple way of doing this
>>> a = (0, 1, 2)
>>> b = (0, 3, 1, 4, 2)
>>> filter(set(a).__contains__, b) == a
True
For greater efficiency use itertools
>>> from itertools import ifilter, imap
>>> from operator import eq
>>> all(imap(eq, ifilter(set(a).__contains__, b), a))
True
This should get you started
>>> A = (0, 1, 2)
>>> B = (0, 3, 1, 4, 2)
>>> b_idxs = {v:k for k,v in enumerate(B)}
>>> idxs = [b_idxs[i] for i in A]
>>> idxs == sorted(idxs)
True
If the list comprehension throws a KeyError, then obviously the answer is also False
Here's a linear time approach (in the longest set) that doesn't require any hashing. It takes advantage of the fact that, since both sets are ordered, earlier items in the set don't need to be re-checked:
>>> def subset_test(a, b):
... b = iter(b)
... try:
... for i in a:
... j = b.next()
... while j != i:
... j = b.next()
... except StopIteration:
... return False
... return True
...
A few tests:
>>> subset_test((0, 1, 2), (0, 3, 1, 4, 2))
True
>>> subset_test((0, 2, 1), (0, 3, 1, 4, 2))
False
>>> subset_test((0, 1, 5), (0, 3, 1, 4, 2))
False
>>> subset_test((0, 1, 4), (0, 3, 1, 4, 2))
True
I'm pretty sure this is right -- let me know if you see any problems.
This should be pretty quick, but I have a faster one in mind I hope to have down soon:
def is_sorted_subset(A, B):
try:
subset = [B.index(a) for a in A]
return subset == sorted(subset)
except ValueError:
return False
Update: here's the faster one I promised.
def is_sorted_subset(A, B):
max_idx = -1
try:
for val in A:
idx = B[max_idx + 1:].index(val)
if max(idx, max_idx) == max_idx:
return False
max_idx = idx
except ValueError:
return False
return True
What about this?
>>> a = (0, 1, 2)
>>> b = (0, 3, 1, 4, 2)
>>> set(a).issubset(set(b))
True
In this example a and b have ordered and unique elements and it checks if a is subset of b. Is this you want?
EDIT:
According to #Marcos da Silva Sampaio: "I want to test if A is a subset of the ordered set B."
It wouldn't be the case of:
>>> a = (2, 0, 1)
>>> b = (0, 3, 1, 4, 2)
>>> set(b).issuperset(a)
True
In this case the order of a doesn't matters.

Resources