Qubix
Qubix

Reputation: 4353

Construct list of consecutive pairs from list of lists

I have an input of the form:

[[41.0, 42.0], [42.0, 17.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]

How can I sort these pairs and keep just the consecutive ones (by consecutive I mean [a, b] where b is the next element, larger than a, but not necessarily in an increment of 1.).

EDIT: My attempt:

test_lst = [[41.0, 42.0], [42.0, 17.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]
new_lst = []
for elem in test_lst:
    if elem[1] > elem[0]:
        new_lst.append(elem)

where new_lst looks like:

[[41.0, 42.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]

Now, for example, for the groups [17.0, 46.0] and [17.0, 29.0], I want to keep just the second one in my list, so the one with the smallest difference between elem[1] and elem[0].

EDIT 2 :

test_lst = [[41.0, 42.0], [42.0, 17.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]

sorted_lst = sorted(test_lst, key = lambda x: int(x[0]))

which gives:

[[6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 46.0], [17.0, 29.0], [29.0, 30.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [41.0, 42.0], [42.0, 17.0], [46.0, 47.0]]

Now all I need to do is, in the case of repeating first element, keep the pair with the smallest second element. How can I do that?

Upvotes: 0

Views: 96

Answers (5)

blhsing
blhsing

Reputation: 106543

You can pair the adjacent items in the list by zipping the list with itself but with one index apart, and since you apparently want the last item despite it not having a next item to compare to, you can manually add it to the list after reversing it so that it will always match. The following example assumes that your list is stored in variable lst:

[[a, b] for (a, b), (n, _) in zip(lst, lst[1:] + [lst[-1][::-1]]) if b == n and b > a]

This returns:

[[41.0, 42.0], [17.0, 46.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]

Note that the third item [46.0, 47.0] in your expected output is incorrect because it is actually followed by [33.0, 34.0] in your original list, whose first element is not 47.0.

And if you want to keep the items with the smallest second item when the first items duplicate, you can sort the list by the first item first, and the second item in reverse order, so that you can use the dict constructor to convert the list of two-item sublists into a dict to eliminate duplicates, and then convert the dict items to a list of sublists by mapping them to the list constructor:

list(map(list, dict(sorted([(a, b) for (a, b), (n, _) in zip(lst, lst[1:] + [lst[-1][::-1]]) if b == n and b > a], key=lambda t: (t[0], -t[1]))).items()))

This returns:

[[6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [41.0, 42.0]]

Upvotes: 0

user2390182
user2390182

Reputation: 73460

Since there are floats involved you should take some precautions when checking for exact equality:

e = 0.0000001  # some epsilon value accounting for imprecision
sorted(x for x in lst if abs(x[1]-x[0]-1) <= e)
# [[6.0, 7.0], [29.0, 30.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [41.0, 42.0], [46.0, 47.0]]

Upvotes: 2

Mark
Mark

Reputation: 5239

You can do something like:

values = [[41.0, 42.0], [42.0, 17.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]

sortedValues = []

for value in values:
    if value[1] > value[0]:
        sortedValues.append(value)

print(sortedValues)

Upvotes: 0

Micha Wiedenmann
Micha Wiedenmann

Reputation: 20843

Use list comprehension:

>>> [x for x in a if x[0] + 1 == x[1]]
[[41.0, 42.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [6.0, 7.0], [29.0, 30.0]]

Then sort it:

>>> sorted([x for x in a if x[0] + 1 == x[1]], key=lambda x: x[0])
[[6.0, 7.0], [29.0, 30.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [41.0, 42.0], [46.0, 47.0]]

Upvotes: 1

onno
onno

Reputation: 979

outer_list = [[41.0, 42.0], [42.0, 17.0], [17.0, 46.0], [46.0, 47.0], [33.0, 34.0], [34.0, 35.0], [35.0, 36.0], [36.0, 7.0], [36.0, 6.0], [6.0, 7.0], [7.0, 12.0], [12.0, 17.0], [17.0, 29.0], [29.0, 30.0]]
new_outer_list = []
for inner_list in outer_list:
    if inner_list[0]+1 == inner_list[1]:
        new_outer_list.append(inner_list)

Upvotes: 0

Related Questions