Find pattern of elements between multiple lists - python

Take these lists:
[545, 766, 1015]
[546, 1325, 2188, 5013]
[364, 374, 379, 384, 385, 386, 468, 496, 497, 547]
My actual pattern is just finding numbers that are ascending by one, only one from each list (For this example, would be 545, 546 and 547).
After actually finding this exists, I want the first number in the sequence to be returned to me so I can continue with my other calculations.
Preferred code execution example:
>>>[12, 64, 135, 23] # input lists
>>>[84, 99, 65]
>>>[66, 234, 7, 43, 68]
>>>[64, 65, 66] # found numbers by said pattern.
>>>return 64
I have not thought of any function worthy to be written ...

A series is valid only for all numbers in the first list only if n+1 is in the next list, n+2 in the one after etc.
You can use set operations and short-circuiting with all to make searching efficient:
lists = [[545, 766, 1015],
[546, 1325, 2188, 5013],
[364, 374, 379, 384, 385, 386, 468, 496, 497, 547],
]
sets = list(map(set, lists))
out = [x for x in lists[0] if all(x+i in s for i, s in enumerate(sets[1:], start=1))]
Output:
[545]
as a function:
def find_successive(lists):
sets = list(map(set, lists[1:]))
return [x for x in lists[0] if all(x+i in s for i, s in
enumerate(sets, start=1))
]
find_successive([[12, 64, 135, 23],[84, 99, 65],[66, 234, 7, 43, 68]])
# [64]
find_successive([[12, 64, 135, 23],[84, 99, 65, 24],[66, 234, 7, 25, 43, 68]])
# [64, 23]
Alternative approach, still using sets for efficiency. Generate sets of the lists, removing 1 for the second list values, 2 for the third, etc. Then find the sets intersection:
def find_successive(lists):
sets = [{x-i for x in l} for i,l in enumerate(lists)]
return set.intersection(*sets)
# or, shorter syntax
def find_successive(lists):
return set(lists[0]).intersection(*({x-i for x in l} for i, l in enumerate(lists[1:], start=1)))
find_successive([[12, 64, 135, 23],[84, 99, 65, 24],[66, 234, 7, 25, 43, 68]])
# {23, 64}

def search(a,b,c):
for val in a:
if (val+1) in b and (val+2) in c:
return val
print(search([545, 766, 1015],[546, 1325, 2188, 5013],[364, 374, 379, 384, 385, 386, 468, 496, 497, 547]))

Related

List of tuples from original list

I have a list [6, 63, 131, 182, 507, 659, 669]
and would like to create a new list of pairs that looks like this:
[(7,63),(64,131),(132,182),(183,507),(508,659),(660,669)]
When I use the below code:
list = [6, 63, 131, 182, 507, 659, 669]
line_num = 0
for idx,i in enumerate(list):
print(list[idx]+1,list[idx+1])
I get below error:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
5 pass
6 else:
----> 7 print(city_index[idx]+1,city_index[idx+1])
IndexError: list index out of range
How do I end the loop before I get an error?
Consider using zip instead. This frees you from worrying about list indices (for the most part).
lst = [6, 63, 131, 182, 507, 659, 669]
for x, y in zip(lst, lst[1:]):
print(x+1, y)
If you don't like the idea of making a shallow copy of lst, use itertools.islice instead.
from itertools import islice
lst = [6, 63, 131, 182, 507, 659, 669]
for x, y in zip(lst, islice(lst, 1, None)):
print(x+1, y)
Or, use itertools.pairwise, introduced in Python 3.10
for x, y in pairwise(lst):
print(x+1, y)
Use slicing, and it returns everything of the message but the last element ie :-1
list = [6, 63, 131, 182, 507, 659, 669]
line_num = 0
for idx,i in enumerate(list[:-1]):
print(list[idx]+1,list[idx+1])
l = [6, 63, 131, 182, 507, 659, 669]
new_l = []
for i in range(1, len(l)):
new_l.append((l[i-1] + 1, l[i]))
print(new_l)
output:
[(7, 63), (64, 131), (132, 182), (183, 507), (508, 659), (660, 669)]
You loop until the length of the list - 1 to avoid out of range:
lst = [6, 63, 131, 182, 507, 659, 669]
pairs = []
for i in range(len(lst)-1):
pairs.append((lst[i]+1, lst[i+1]))
nums = [6, 63, 131, 182, 507, 659, 669]
pairs = [(nums[i] + 1, nums[i + 1]) for i in range(len(nums) - 1)]
You could do this in a list comprehension and stop the loop at len(nums) - 1 instead of len(nums). You probably don't want to call a variable list because that's a special word in python.

How to check if two lists don't have similarites?

I need to find a method to check if two json files don't have similarities within each other.
Here is an example of an array of two json files:
[32, 19, 1, 2, 71, 171, 95, 92, 38, 3]
[196, 167, 67, 112, 114, 25, 105, 7, 26, 32]
As you can see, both of these arrays contains "32".
How can I check if there is no similarities beetween their values in the array?
Convert your JSON to lists using json.load(file)
Then, add one list to a set and check all elements of the next list against it
>>> l1 = [32, 19, 1, 2, 71, 171, 95, 92, 38, 3]
>>> l2 = [196, 167, 67, 112, 114, 25, 105, 7, 26, 32]
>>> s1 = set(l1)
>>> any(x in s1 for x in l2)
True
You can do the same within a set (change x in s1 to x in l1) but it'll be less optimal
You can use a set's isdisjoint method
if set(list1).isdisjoint(list2):
print("there are no commonalities")
else:
print("there is at least one common element")
I agree with above two solution, they have used set and still iterating over it. If need to iterate set, then whats needs to have set.
set(list) will take linear time to build set and again iterate the set.
Here is simple solution depicting the same.
l1 = [32, 19, 1, 2, 71, 171, 95, 92, 38, 3]
l2 = [196, 167, 67, 112, 114, 25, 105, 7, 26]
print(any(x in l1 for x in l2))
def compare(list1,list2):
for i in list1:
if(i in list2):
return True
return False
list1 = '{"a":[32, 19, 1, 2, 71, 171, 95, 92, 38, 3]}'
list2 = '{"b":[196, 167, 67, 112, 114, 25, 105, 7, 26, 32]}'
list1=list(json.loads(list1).values())
list2=list(json.loads(list2).values())
print(compare(list1[0],list2[0]))

how to get original numbers from a list after computing the difference between to consecutive numbers

{0: [41, 42, 183, 186, 471, 493, 639, 642, 732, 734], 1: [477, 489, 490]}
consider I have a dictionary with a list as values.
I want to find the difference between two consecutive numbers in the list and if their difference is less than, say 40, I want to fetch the second consecutive number of those two numbers taken into consideration and store all such kinds of numbers in a list.
Can anyone please help me with this.
One way to approach this:
data = {0: [41, 42, 183, 186, 471, 493, 639, 642, 732, 734], 1: [477, 489, 490]}
x = 40
{k: [b for a, b in zip(v, v[1:]) if a + x > b] for k, v in data.items()}
# {0: [42, 186, 493, 642, 734], 1: [489, 490]}
Or for a flat list:
[b for v in data.values() for a, b in zip(v, v[1:]) if a + 40 > b]
# [42, 186, 493, 642, 734, 489, 490]

Python - re.split string

I've been searching for a solution for a few hours now. I have a variable I want to split up in a nested list.
points ="""M445,346c28.8,0,56,11.2,76.4,31.6C541.8,398,553,425.2,553,454s-11.2,56-31.6,76.4C501,550.8,473.8,562,445,562
s-56-11.2-76.4-31.6C348.2,510,337,482.8,337,454s11.2-56,31.6-76.4S416.2,346,445,346 M445,345c-60.2,0-109,48.8-109,109
s48.8,109,109,109s109-48.8,109-109S505.2,345,445,345L445,345z"""
newPoints = re.split(r'[A-Za-z-]', points)
It is a multiline var with x and y positions of points from a svg file.
The pattern is that it starts a new item at a letter. I would like to have it ordered something like the following. I've tried some options like above. One of the mail problems is that it keeps deleting my delimiter. :)
[
[
[command],
[x of p1, y of p1],
[x of p2, y of p2],
[x of p3, y of p3]
]
]
[
[ [M],[445,346] ],
[ [c],[28.8,0],[56,11.2],[76.4,31.6] ]
]
Any pointers are very welcome!
You can find letters and floats, and then group:
import re
import itertools
points ="""M445,346c28.8,0,56,11.2,76.4,31.6C541.8,398,553,425.2,553,454s-11.2,56-31.6,76.4C501,550.8,473.8,562,445,562
s-56-11.2-76.4-31.6C348.2,510,337,482.8,337,454s11.2-56,31.6-76.4S416.2,346,445,346 M445,345c-60.2,0-109,48.8-109,109
s48.8,109,109,109s109-48.8,109-109S505.2,345,445,345L445,345z"""
new_points = [list(b) for a, b in itertools.groupby(filter(None, re.findall('[a-zA-Z]+|[\d\.]+', points)), key=lambda x:re.findall('[a-zA-Z]+', x))]
final_data = [[new_points[i], [int(c) if re.findall('^\d+$', c) else float(c) for c in new_points[i+1]]] for i in range(0, len(new_points)-1, 2)]
Output:
[[['M'], [445, 346]], [['c'], [28.8, 0, 56, 11.2, 76.4, 31.6]], [['C'], [541.8, 398, 553, 425.2, 553, 454]], [['s'], [11.2, 56, 31.6, 76.4]], [['C'], [501, 550.8, 473.8, 562, 445, 562]], [['s'], [56, 11.2, 76.4, 31.6]], [['C'], [348.2, 510, 337, 482.8, 337, 454]], [['s'], [11.2, 56, 31.6, 76.4]], [['S'], [416.2, 346, 445, 346]], [['M'], [445, 345]], [['c'], [60.2, 0, 109, 48.8, 109, 109]], [['s'], [48.8, 109, 109, 109]], [['s'], [109, 48.8, 109, 109]], [['S'], [505.2, 345, 445, 345]], [['L'], [445, 345]]]

Generate list of all palindromic numbers of 3 digits in python

I want to generate list of all palindromic numbers of 3 digits in python. I can code this in a crude way but is there some intuitive way using list comprehension or itertools etc?
And also, How to do it if it is given the number is k digits instead of just 3?
>>> L = [int("%d%d%d" % (x,y,x)) for x in range(1,10) for y in range(10)]
>>> L
[101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252,
262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414,
424, 434, 444, 454, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575,
585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 696, 707, 717, 727, 737,
747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898,
909, 919, 929, 939, 949, 959, 969, 979, 989, 999]
UPDATE: To be more memory and speed efficient, you can replace string formatting and int conversion by x+y*10+x*100. Thanks #larsmans.
UPDATE 2: And that's for k digits!
[int(''.join(map(str, (([x]+list(ys)+[z]+list(ys)[::-1]+[x]) if k%2
else ([x]+list(ys)+list(ys)[::-1]+[x])))))
for x in range(1,10)
for ys in itertools.permutations(range(10), k/2-1)
for z in (range(10) if k%2 else (None,))]
And that's optimized to NOT use strings!
[sum([n*(10**i) for i,n in enumerate(([x]+list(ys)+[z]+list(ys)[::-1]+[x]) if k%2
else ([x]+list(ys)+list(ys)[::-1]+[x]))])
for x in range(1,10)
for ys in itertools.permutations(range(10), k/2-1)
for z in (range(10) if k%2 else (None,))]
I used permutations, and a different loop for the first digit, which cannot be 0, and the last loop is to add all possible digits in the middle if k%2 == 1 (k is odd).
Suggestions to optimize this are welcome!
For the generalisation to k digits, the most obvious way is to do something like:
palindromes = [x for x in itertools.permutations(string.digits, k) if x == x[::-1]]
But it isn't very efficient - it generates every possible 3-digit number, and discards the ones that aren't palindromes. However, it is possible to generalise solutions like #jadkik94's - what you need to do is generate every combination of half the length (rounding down), and stick the mirror of it on the end:
palindromes = [x + x[::-1] for x in permutations(digits, k//2)]
Will work for all even k - for odd k, you add an extra loop to put all of 0-9 in between the mirrored halves.
The simplest way would be converting the numbers to strings and checking if they are palindromes. To find the palindromes of the "k" number of digits, the list comprehension could be;
palindromes = [num for num in range(pow(10,k-1),pow(10,k)) if str(num) == str(num)[::-1]]

Categories

Resources