Related
I have an ordered list of entities, numbered in a broken sequence:
[1, 2, 3, 6, 7, 11, 17, 18, 19]
I'd like to break the list where there's a gap, and collect the results in a new list:
[[1, 2, 3], [6, 7], [11], [17, 18, 19]]
I have the feeling there's a name for what I want to do and probably a nice library function for it - but I can't think of it. Can anyone shine some light before I possibly reinvent a wheel?
edit: Thanks, folks, but I was asking if there's a name for this operation and an existing algorithm, not for implementations - this is what I came up with:
def group_adjoining(elements, key=lambda x: x):
"""Returns list of lists of contiguous elements
:key: function to get key integer from list element
"""
if not elements:
return elements
result = [[elements[0]]]
for a, b in zip(elements, elements[1:]):
if key(a) + 1 == key(b):
result[-1].append(b)
else:
result.append([b])
return result
Plain itertools.groupby approach:
from itertools import groupby
lst = [1, 2, 3, 6, 7, 11, 17, 18, 19]
out = []
for _, g in groupby(enumerate(lst), lambda x: x[0] - x[1]):
out.append([v for _, v in g])
print(out)
Prints:
[[1, 2, 3], [6, 7], [11], [17, 18, 19]]
Try greedy approach:
lst = [1, 2, 3, 6, 7, 11, 17, 18, 19]
res = []
tmp = []
prv = lst[0]
for l in lst:
if l-prv > 1:
res.append(tmp)
tmp = []
tmp.append(l)
prv = l
res.append(tmp)
print(res)
Output: [[1, 2, 3], [6, 7], [11], [17, 18, 19]]
I first came across more_itertools today, and I think this package is useful for this problem.
pip install more-itertools
from more_itertools import split_when
l = [1, 2, 3, 6, 7, 11, 17, 18, 19]
res = list(split_when(l, lambda a, b: a + 1 != b))
print(res)
You could use a simple generator.
def split(lst):
result = []
for item in lst:
if (not result) or result[-1] + 1 == item:
result.append(item)
else:
yield result
result = [item]
if result:
yield result
foo = [1, 2, 3, 6, 7, 11, 17, 18, 19]
result = [i for i in split(foo)]
print(result) # [[1, 2, 3], [6, 7], [11], [17, 18, 19]]
This assumes a sorted homogeneous list of int.
You could always avoid the sorted assumption with for item in sorted(lst):.
It's pretty easy by using this simple function:
li = [1, 2, 3, 6, 7, 9, 10, 11, 12, 14, 16, 17, 18]
def split(li):
result = []
temp = [li[0]]
for i in range(1, len(li)):
if li[i] - temp[-1] == 1:
temp.append(li[i])
else:
result.append(temp)
temp = [li[i]]
result.append(temp)
return result
print(split(li))
I have two lists, I want to sort the first one so I get them in ascending order, but I need the second list elements to be sorted with the element of the other list which they originally corresponded and I have no clue how to do that. Example:
Original imput:
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
l1.sort()
Expected Result:
l1 = [1, 6, 13, 31, 42, 99]
l2 = [5, 7, 14 ,11, 15, 12]
Pack them in a tuple and sort it, then unpack as needed:
t = tuple(zip(l1, l2))
l_sorted = sorted(t, key=lambda e: e[0])
l1 = [e[0] for e in l_sorted]
l2 = [e[1] for e in l_sorted]
You can use sorted.
def sort_list(list1, list2):
zipped_pairs = zip(list2, list1)
j=sorted(zipped_pairs)
z = [x for _, x in j]
m = [__ for __, y in j]
print(z,m)
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
print(sort_list(l1, l2))
Its faster if you can use numpy arrays. For example
import numpy as np
arr1 = np.array([13, 1, 31, 6, 42, 99])
arr2 = np.array([14, 5, 11 ,7, 15, 12])
arr1_sorted = np.sort(arr1)
arr2_sorted = arr2[arr1.argsort()]
# The expected answer would be
# arr1_sorted = array([1, 6, 13, 31, 42, 99])
# arr2_sorted = array([5, 7, 14 ,11, 15, 12])
Here sort() returns the sorted array, while argsort() returns the index corresponding to a sorted array
Unlikely to be fastest solution, but beautiful to my eye :)
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
def delegated_sort(l1, l2):
return map(list, zip(*sorted(zip(l1, l2))))
>>> delegated_sort(l1, l2)
[[1, 6, 13, 31, 42, 99], [5, 7, 14, 11, 15, 12]]`
array1=[3, 7, 11, 12, 15, 5, 1, 4]
array2=[14, 10, 9, 16, 2, 13, 6, 8]
I shuffled these arrays.
shuffled1 = sorted(array1, key=lambda k: random.random())
shuffled2 = sorted(array2, key=lambda k: random.random())
However, I do not want the same numbers to come to the same indexes again. For example: 3 and 14 at index 0, 7 and 10 at index 1. I don't want these numbers to be reciprocal again. All numbers need to be couple with another number.
For example:
shuffled1 =[1, 15, 4, 12, 7, 5, 3, 11]
shuffled2 =[13, 8, 9, 14, 2, 16, 6, 10]
İf shuffled arrays not like this, shuffle again.
As first step you can create a dictionary that will be used if shuffled lists array1 and array2 don't contain the values from initial state. Then we repeat shuffling until the condition is met.
For example:
from random import random
array1=[3, 7, 11, 12, 15, 5, 1, 4]
array2=[14, 10, 9, 16, 2, 13, 6, 8]
disallowed_dict = {}
for a, b in zip(array1, array2):
disallowed_dict.setdefault(a, []).append(b)
while any(b in disallowed_dict[a] for a, b in zip(array1, array2)):
array1 = sorted(array1, key=lambda _: random())
array2 = sorted(array2, key=lambda _: random())
print(array1)
print(array2)
Prints (for example):
[1, 15, 4, 7, 5, 11, 12, 3]
[16, 6, 10, 13, 8, 14, 9, 2]
I had completely missread the condition. Try this:
import numpy as np
from random import randint
array1=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def my_shuffle(array1, array2):
narray1 = np.array(array1)
idxs = []
for element in array1:
idx = randint(0,len(array1)-1)
while idx in idxs:
idx = randint(0,len(array1)-1)
idxs.append(idx)
narray1[idx] = element
narray2 = np.array(array2)
it = 0
idxs2 = []
for element in array2:
idx = randint(0,len(array2)-1)
while idx in idxs2 or idx == idxs[it]:
idx = randint(0,len(array2)-1)
idxs2.append(idx)
it+=1
narray2[idx] = element
return narray1, narray2
new1, new2 = my_shuffle(array1, array1)
print(f"{new1}\n{new2}")
I'm a novice coding learner.
I am trying to extract numbers only in sequential from the list.
for example, my list is:
s = [2, 4, 6, 7, 8, 9, 10, 13, 14, 15]
from this list I want only the numbers in sequential:
6,7,8,9,10, 13,14,15
so, I have the following code, but it doesn't work.
s = [2, 4, 6, 7, 8, 9, 10, 13, 14, 15]
for i in s:
if s[i+1] - s[i] == 1:
print(s[i])
could you give me some idea? Thank you.
I just solved this question. thank you all for commenting.
s = [2, 4, 6, 7, 8, 9, 10, 13, 14, 15]
a = []
for i in range(len(s)-1):
if s[i] - s[i+1] == -1:
a. append(s[i])
a. append(s[i+1])
print(set(a))
I would iterate through the list s storing the results in set res and at the end, if I want the results sorted, I would apply the sorted function on res to get the output.
Here is some code.
s= [2, 4, 6, 7, 8, 9, 10, 13, 14, 15]
res = set()
for i, num in enumerate(s[:-1]):
if num+1 == s[i+1]:
res = res.union({num} )
res = res.union({s[i+1]})
print(sorted(res))
print(res)
And the output is:
>>> [6, 7, 8, 9, 10, 13, 14, 15]
{6, 7, 8, 9, 10, 13, 14, 15}
Keep in mind that sets are NOT sorted even if they appear to be sorted. This is because sets DO NOT support indexes. So if you want your results sorted, make sure to apply the sorted function to be on the safe side.
you are looping over the items of the list instead of the indices of these items. To loop over the indices use:
if s[1] - s[0] == 1:
print(s[0])
for i in range(1,len(s)):
if s[i] - s[i-1] == 1:
print(s[i])
I need to compare every item in a very long list (12471 items) to every other item in the same list. Below is my list:
[array([3, 4, 5])
array([ 6, 8, 10])
array([ 9, 12, 15])
array([12, 16, 20])
array([15, 20, 25])
...] #12471 items long
I need to compare the second item of each array to the first item of every other array to see if they're equal. And preferably, in a very efficient way. Is there a simple and efficient way to do this in Python 2.x?
I worked up a very crude method here, but it is terribly slow:
ls=len(myList) #12471
l=ls
k=0
for i in myList:
k+=1
while l>=0:
l-=1
if i[1]==myList[l][0]:
#Do stuff
l=ls
While this is still theoretically N^2 time (worst case), it should make things a bit better:
import collections
inval = [[3, 4, 5],
[ 6, 8, 10],
[ 9, 12, 15],
[ 12, 14, 15],
[12, 16, 20],
[ 6, 6, 10],
[ 8, 8, 10],
[15, 20, 25]]
by_first = collections.defaultdict(list)
by_second = collections.defaultdict(list)
for item in inval:
by_first[item[0]].append(item)
by_second[item[1]].append(item)
for k, vals in by_first.items():
if k in by_second:
print "by first:", vals, "by second:", by_second[k]
Output of my simple, short case:
by first: [[6, 8, 10], [6, 6, 10]] by second: [[6, 6, 10]]
by first: [[8, 8, 10]] by second: [[6, 8, 10], [8, 8, 10]]
by first: [[12, 14, 15], [12, 16, 20]] by second: [[9, 12, 15]]
Though this DOES NOT handle duplicates.
We can do this in O(N) with an assumption that python dict takes O(1) time for insert and lookup.
In the first scan, we create a map storing first number and row index by scanning the full list
In the second scan, we find if map from first scan contains second element of each row. If map contains then value of map gives us the list of row indices that match the required criterion.
myList = [[3, 4, 5], [ 6, 8, 10], [ 9, 12, 15], [12, 16, 20], [15, 20, 25]]
first_column = dict()
for idx, list in enumerate(myList):
if list[0] in first_column:
first_column[list[0]].append(idx)
else:
first_column[list[0]] = [idx]
for idx, list in enumerate(myList):
if list[1] in first_column:
print ('rows matching for element {} from row {} are {}'.format(list[1], idx, first_column[list[1]]))