Merging intervals in Python - python

I am very new to Python programming and have come across a problem statement i have no clue how to solve.
I have four lines of input:
0 1
2 4
6 7
3 5
For accepting these 4 lines of input i can do the below:
for i in range(4):
a,b = list(map(int,input().split(' ')))
I am supposed to merge the intervals into(Output) :
0 1
2 5
6 7
Intervals (2,4) and (3,5) they should be merged into one (2,5).
I am not sure how should i go about this ?
Can someone help me in getting a direction?
Thanks in advance.

If you're looking for a Python library that handles intervals arithmetic, consider python-interval. Disclaimer: I'm the maintainer of that library.
import intervals as I
interval = I.empty()
for i, j in [(0, 1), (2, 4), (6, 7), (3, 5)]:
interval = interval | I.closed(i, j)
print(interval)
results in
[0,1] | [2,5] | [6,7]
See its documentation for more information.

Try this
from functools import reduce
# inp = [(0,1),(2,9),(6,7),(3,5)]
inp = [(0,1),(2,4),(6,7),(3,5)]
print(inp)
def merge(li,item):
if li:
if li[-1][1] >= item[0]:
li[-1] = li[-1][0], max(li[-1][1],item[1])
return li
li.append(item)
return li
print(reduce(merge, sorted(inp), []))

Related

How make a especific combinations in python?

I'm trying to make a specific combination so that it adds up to "4" by adding the following specs:
a+a+a+a+a+a+a+a = 0.5 per/unit = (In total it sum:) 4
b+b+b+b = 1 per/unit = (In total it sum:) 4
c+c = 2 per/unit = (In total it sum:) 4
That way I want to know the result and print the combinations on the screen:
a+a+a+a+a+a+a+a = 4
a+a+a+a+a+a+b = 4
a+a+a+a+b+b = 4
a+a+b+b+b = 4
a+a+a+a+a+a+c = 4
a+a+b+c = 4
a+a+c+b = 4
b+a+a+a+a+a+a = 4
b+b+a+a+a+a = 4
b+b+b+a+a = 4
b+b+c = 4
b+c+a+a = 4
b+a+c = 4
b+c+a = 4
c+a+a+a+a = 4
c+b+a+a = 4
c+a+a+b = 4
My code:
from itertools import combinations
numbers=[2,4,8]
for c in combinations(numbers, 3):
print(c)
Is there a way to do it that specific way?
Thanks very much for readme.
I'll try to answer you question in a didactically fashion without supplying the full code (as you requested in the comment above).
combinatory approach
The straight forward solution would be to just look at possible combinations of the numbers array for different lengths. Looping over the lengths as well as over the combinations you can check whether the sum over these elements gives your solution.
You should look at the function itertools.combinations_with_replacement as it allows multiple occurrances of each element.
from itertools import combinations_with_replacement
numbers=[2,4,8]
for length in [3]:
for c in combinations_with_replacement(numbers, length):
print(c, f"sum {sum(c)}")
> (2, 2, 2) sum 6
> (2, 2, 4) sum 8
> (2, 2, 8) sum 12
> (2, 4, 4) sum 10
> (2, 4, 8) sum 14
> (2, 8, 8) sum 18
> (4, 4, 4) sum 12
> (4, 4, 8) sum 16
> (4, 8, 8) sum 20
> (8, 8, 8) sum 24
You would have to specify the length-array accordingly and add an if-clause for printing.
functional approach:
Assume the function you are looking for is defined as def calcComb(sum,numbers): ... which returns a string of combinations you have tried.
The typical functional solution to this problem is recursively calling an inner function rec(sumRest,numRest,textComb) that keeps track of the sum your building up as well as the combination (here in string format) you are testing. The skeletal structure would be something like:
def rec(sumRest,numRest,textComb):
if ... : return ...
elif ... : return ...
else :
newText = ...
return rec(sumRest-numRest[0],numRest,textComb+newText)
+ rec(sumRest,numRest[1:],textComb)
edit :
The above approaches are straight-forward implementations of the problem and are not optimized with respect to performance. If your problem scales up you might be interested to save the state of previous calculation steps (dynamic approach) or cache intermediate results in a dicationary (memoization).

Python Comprehension - Replace Nested Loop

Working on the 'two-sum' problem..
Input: An unsorted array A (of integers), and a target sum t
The goal: to return a list of tuple pairs (x,y) where x + y = t
I've implemented a hash-table H to store the contents of A. Through use of a nested loop to iterate through H, I'm achieving the desired output. However, in the spirit of learning the art of Python, I'd like to replace the nested loop with a nice 1-liner using comprehension & a maybe lambda function? Suggestions?
Source Code:
import csv
with open('/Users/xxx/Developer/Algorithms/Data Structures/_a.txt') as csvfile:
csv_reader = csv.reader(csvfile, delimiter ='\n')
hash_table = {int(num[0]):int(num[0]) for(num) in csv_reader} #{str:int}
def two_sum(hash_table, target):
pairs = list()
for x in hash_table.keys():
for y in hash_table.keys():
if x == y:
continue
if x + y == target:
pairs.append((x,y))
return pairs
When you have two ranges and you want to loop both of them separately to get all the combinations as in your case, you can combine the loops into one using itertools.product. You can replace the code below
range1 = [1,2,3,4]
range2 = [3, 4, 5]
for x in range1:
for y in range2:
print(x, y)
with
from itertools import product
for x, y in product(range1, range2):
print(x, y)
Both code blocks produce
1 3
1 4
1 5
2 3
2 4
2 5
3 3
3 4
3 5
4 3
4 4
4 5
But you would still need the if check with this construct. However, what product returns is a generator and you can pass that as the iterable to map or filter along with a lambda function.
In your case you only want to include pairs that meet the criteria. Thus, filter is what you want. In my simple example, if we only want combinations whose sum is even, then we could do something like
gen = product(range1, range2)
f = lambda i: (i[0] + i[1]) % 2 == 0
desired_pairs = filter(f, gen)
This can be written as a one-liner like
desired_pairs = filter(lambda i: (i[0] + i[1]) % 2 == 0, product(range1, range2))
without being too complicated for being understood.
Note that like product and map, what filter returns is a generator, which is good if you are just going to loop over it later to do some other work. If you really need a list just do convert it to a list as
desired_pairs = list(filter(lambda i: (i[0] + i[1]) % 2 == 0, product(range1, range2)))
If we print this we get
[(1, 3), (1, 5), (2, 4), (3, 3), (3, 5), (4, 4)]

Creating a dictionary with calculated values

I have a large text string and I would like to create a dictionary with a key = a pair of words (have to go through all possible combinations) in the string and the value = frequency of a given pair of words. Thus, it is a 2D matrix and each matrix element is a number (a frequency of the pair from a column and a row crossing each other. The position of the words in the pair is irrelevant: e.g. if ridebike = 4 (a frequency) then bikeride = 4 as well
The end result is to populate the matrix and then select N number of top pairs.
I am new working with text strings and with Python in general and I got hopelessly lost (also way too many loops in my "code")
This is what I have (after deleting stopwords and punctuations):
textNP = 'stopped traffic bklyn bqe 278 wb manhattan brtillary stx29 wb cadman pla hope oufootball makes safe manhattan kansas tomorrow boomersooner beatwildcats theyhateuscuztheyaintus hatersgonnahate rt bringonthecats bring cats exclusive live footage oklahoma trying get manhattan http colktsoyzvvz rt jonfmorse bring cats exclusive live footage oklahoma trying get manhattan'
Some code (incomplete and wrong):
txtU = set(textNP)
lntxt = len(textNP)
lntxtS = len(txtU)
matrixNP = {}
for b1, i1 in txtU:
for b2, i2 in txtU:
if i1< i2:
bb1 = b1+b2
bb2 = b2+b1
freq = 0
for k in textNP:
for j in textNP:
if k < j:
kj = k+j
if kj == bb1 | kj == bb2:
freq +=1
matrixNP[i1][i2] = freq
matrixNP[i2][i1] = freq
elif i1 == i2: matrixNP[i1][i1] = 1
One of the issues that I am certain that having many loops is wrong. Also, I am not sure how to assign calculated keys (concatenation of words) to a dictionary (I think I got the values correctly)
The text string is not a complete product: it will be cleaned from numbers and few other things with various regexs
Your help will be very much appreciated!
Are you looking for all combinations of 2 words, if so you can use itertools.combinations and a collections.Counter to do what you want:
>>> from itertools import combinations
>>> from collections import Counter
>>> N = 5
>>> c = Counter(tuple(sorted(a)) for a in combinations(textNP.split(), 2))
>>> c.most_common(N)
[(('manhattan', 'rt'), 8),
(('exclusive', 'manhattan'), 8),
(('footage', 'manhattan'), 8),
(('manhattan', 'oklahoma'), 8),
(('bring', 'manhattan'), 8)]
Or are you looking for all pairs of consecutive words then you can create a pairwise function:
>>> from itertools import tee
>>> from collections import Counter
>>> def pairwise(iterable):
... a, b = tee(iterable)
... next(b, None)
... return zip(a, b) # itertools.izip() in python2
>>> N = 5
>>> c = Counter(tuple(sorted(a)) for a in pairwise(textNP.split()))
>>> c.most_common(N)
[(('get', 'manhattan'), 2),
(('footage', 'live'), 2),
(('get', 'trying'), 2),
(('bring', 'cats'), 2),
(('exclusive', 'live'), 2)]
Neither way do I see bike ride in the list.

what's wrong with my solution?Count of Maximum[Code Chef]

Question.This is simple question yet i don't know what's wrong with this code?
from collections import Counter
def com(N,A):
num_array=A.split()
c=Counter(num_array)
C=max(c.values())
l1=[]
for k in c:
if c[k]==C:
l1.append(k)
V1=min(l1)
V=int(V1)
print V,C
t=input()
for i in range(t):
N=input()
A=raw_input()
com(N,A)
If possible any simpler solution would be great
You need to convert the values in l1 to integers before taking the min. Otherwise you are taking the min of strings.
This will get you started:
from collections import Counter
li='''2
5
1 2 3 2 5
6
1 2 2 1 1 2'''.splitlines()
c=Counter()
for e in [s.split(' ') for s in li]:
c.update(e)
print c.most_common(2)
Prints:
[('2', 6), ('1', 4)]

How to split a list into subsets with no repeating elements in python

I need code that takes a list (up to n=31) and returns all possible subsets of n=3 without any two elements repeating in the same subset twice (think of people who are teaming up in groups of 3 with new people every time):
list=[1,2,3,4,5,6,7,8,9]
and returns
[1,2,3][4,5,6][7,8,9]
[1,4,7][2,3,8][3,6,9]
[1,6,8][2,4,9][3,5,7]
but not:
[1,5,7][2,4,8][3,6,9]
because 1 and 7 have appeared together already (likewise, 3 and 9).
I would also like to do this for subsets of n=2.
Thank you!!
Here's what I came up with:
from itertools import permutations, combinations, ifilter, chain
people = [1,2,3,4,5,6,7,8,9]
#get all combinations of 3 sets of 3 people
combos_combos = combinations(combinations(people,3), 3)
#filter out sets that don't contain all 9 people
valid_sets = ifilter(lambda combo:
len(set(chain.from_iterable(combo))) == 9,
combos_combos)
#a set of people that have already been paired
already_together = set()
for sets in valid_sets:
#get all (sorted) combinations of pairings in this set
pairings = list(chain.from_iterable(combinations(combo, 2) for combo in sets))
pairings = set(map(tuple, map(sorted, pairings)))
#if all of the pairings have never been paired before, we have a new one
if len(pairings.intersection(already_together)) == 0:
print sets
already_together.update(pairings)
This prints:
~$ time python test_combos.py
((1, 2, 3), (4, 5, 6), (7, 8, 9))
((1, 4, 7), (2, 5, 8), (3, 6, 9))
((1, 5, 9), (2, 6, 7), (3, 4, 8))
((1, 6, 8), (2, 4, 9), (3, 5, 7))
real 0m0.182s
user 0m0.164s
sys 0m0.012s
Try this:
from itertools import permutations
lst = list(range(1, 10))
n = 3
triplets = list(permutations(lst, n))
triplets = [set(x) for x in triplets]
def array_unique(seq):
checked = []
for x in seq:
if x not in checked:
checked.append(x)
return checked
triplets = array_unique(triplets)
result = []
m = n * 3
for x in triplets:
for y in triplets:
for z in triplets:
if len(x.union(y.union(z))) == m:
result += [[x, y, z]]
def groups(sets, i):
result = [sets[i]]
for x in sets:
flag = True
for y in result:
for r in x:
for p in y:
if len(r.intersection(p)) >= 2:
flag = False
break
else:
continue
if flag == False:
break
if flag == True:
result.append(x)
return result
for i in range(len(result)):
print('%d:' % (i + 1))
for x in groups(result, i):
print(x)
Output for n = 10:
http://pastebin.com/Vm54HRq3
Here's my attempt of a fairly general solution to your problem.
from itertools import combinations
n = 3
l = range(1, 10)
def f(l, n, used, top):
if len(l) == n:
if all(set(x) not in used for x in combinations(l, 2)):
yield [l]
else:
for group in combinations(l, n):
if any(set(x) in used for x in combinations(group, 2)):
continue
for rest in f([i for i in l if i not in group], n, used, False):
config = [list(group)] + rest
if top:
# Running at top level, this is a valid
# configuration. Update used list.
for c in config:
used.extend(set(x) for x in combinations(c, 2))
yield config
break
for i in f(l, n, [], True):
print i
However, it is very slow for high values of n, too slow for n=31. I don't have time right now to try to improve the speed, but I might try later. Suggestions are welcome!
My wife had this problem trying to arrange breakout groups for a meeting with nine people; she wanted no pairs of attendees to repeat.
I immediately busted out itertools and was stumped and came to StackOverflow. But in the meantime, my non-programmer wife solved it visually. The key insight is to create a tic-tac-toe grid:
1 2 3
4 5 6
7 8 9
And then simply take 3 groups going down, 3 groups going across, and 3 groups going diagonally wrapping around, and 3 groups going diagonally the other way, wrapping around.
You can do it just in your head then.
- : 123,456,789
| : 147,258,368
\ : 159,267,348
/ : 168,249,357
I suppose the next question is how far can you take a visual method like this? Does it rely on the coincidence that the desired subset size * the number of subsets = the number of total elements?

Categories

Resources