Given an example list a = [311, 7426, 3539, 2077, 13, 558, 288, 176, 6, 196, 91, 54, 5, 202, 116, 95] with n = 16 elements (it will be in general a list of an even number of elements).
I wish to create n/4 lists that would be:
list1 = [311, 13, 6, 5]
list2 = [7426, 558, 196, 202]
list3 = [3539, 288, 91, 116]
list4 = [2077, 176, 54, 95]
(The solution is not taking an element every n such as a[i::3] in a for loop because values are excluded as the sliding window moves to the left)
Thanks for the tips!
UPDATE:
Thanks for the solutions which work well for this particular example. I realized however that my problem is a bit more complex than this.
In the sense that the list a is generated dynamically in the sense the list can decrease or increase. Now my issue is the following, say that the list grows of another group i.e. until 20 elements. Now the output lists should be 5 using the same concept. Example:
a = [311, 7426, 3539, 2077, 1 ,13, 558, 288, 176, 1, 6, 196, 91, 54, 1, 5, 202, 116, 95, 1]
Now the output should be:
list1 = [311, 13, 6, 5]
list2 = [7426, 558, 196, 202]
list3 = [3539, 288, 91, 116]
list4 = [2077, 176, 54, 95]
list5 = [1, 1, 1, 1]
And so on for whatever size of the list.
Thanks again!
I'm assuming the length of the list a is a multiple of 4. You can use numpy for your problem.
import numpy as np
a = [...]
desired_shape = (-1, len(a)//4)
arr = np.array(a).reshape(desired_shape).transpose().tolist()
Output:
[[311, 13, 6, 5],
[7426, 558, 196, 202],
[3539, 288, 91, 116],
[2077, 176, 54, 95],
[1, 1, 1, 1]]
Unpack the list into variables or iterate over them as desirable.
Consult numpy.transpose, and reshape to understand their usage.
One option: nested list comprehension.
split in n/4 chunks of 4 items
out = [[a[i+4*j] for j in range(4)]
for i in range(len(a)//4)]
Output:
[[311, 1, 176, 91],
[7426, 13, 1, 54],
[3539, 558, 6, 1],
[2077, 288, 196, 5],
[1, 176, 91, 202]]
split in 4 chunks of n/4 items
out = [[a[i+4*j] for j in range(len(a)//4)]
for i in range(4)]
Output:
[[311, 1, 176, 91, 202],
[7426, 13, 1, 54, 116],
[3539, 558, 6, 1, 95],
[2077, 288, 196, 5, 1]]
To split in lists:
list1, list2, list3, list4 = out
Although it is not easily possible to do this programmatically (and not recommended to use many variables)
Related
As the title says, I have the following array,
arr = [7, 69, 2, 221, 8974]
I then reverse it using either of the following methods
In [01]: arr[::-1]
Out[01]: [8974, 221, 2, 69, 7]
Using .reverse()
In [01]: arr.reverse()
In [02]: print(arr)
Out[02]: [8974, 221, 2, 69, 7]
Using reversed(arr)
In [01]: list(reversed(arr))
Out[01]: [8974, 221, 2, 69, 7]
Clearly in all instances the output should be [8974, 221, 69, 7, 2]
I am using Python 3.9.5. Does anyone know why this behaviour is observed?
I think you want your output to be sorted. You can try code in this way:
arr = [7, 69, 2, 221, 8974]
sorted(arr,reversed=True)
Using .reverse()
In [01]: arr.sort().reverse()
In [02]: print(arr)
Out[02]: [8974, 221, 2, 69, 7]
Using reversed(arr)
In [01]: list(reversed(sorted(arr)))
Out[01]: [8974, 221, 2, 69, 7]
I have the following list:
indices_to_remove: [0,1,2,3,..,600,800,801,802,....,1200,1600,1601,1602,...,1800]
I have basically 3 subsets of consecutive indices:
0-600
800-1200
1600-1800
I would like to create 3 different small lists that will include only consecutive numbers.
Expected outcome:
indices_to_remove_1 : [0,1,2,3,....,600]
indices_to_remove_2 : [800,801,802,....,1200]
indices_to_remove_3 : [1600,1601,1602,....., 1800]
P.S: The numbers are arbitrary and random; moreover, I may encounter more than 3 subsets or less.
Another way is using more_itertools.consecutive_groups:
(used #Stephen's list for an example):
import more_itertools as mit
for group in mit.consecutive_groups(indices_to_remove):
print(list(group))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
[160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]
I like to use generators for this sort of problem. You can do this like:
Split Non-Consecutive Data:
def split_non_consequtive(data):
data = iter(data)
val = next(data)
chunk = []
try:
while True:
chunk.append(val)
val = next(data)
if val != chunk[-1] + 1:
yield chunk
chunk = []
except StopIteration:
if chunk:
yield chunk
Test Code:
indices_to_remove = (
list(range(0, 11)) +
list(range(80, 91)) +
list(range(160, 171))
)
for i in split_non_consequtive(indices_to_remove):
print(i)
Results:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
[160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]
Without making it complicated, you can simply solve it something like this :
def chunk_lists_(data_):
consecutive_list = []
for chunks in range(len(data_)):
try:
#check consecutiveness
if data_[chunks + 1] - data_[chunks] == 1:
#check if it's already in list
if data_[chunks] not in consecutive_list:
consecutive_list.append(data_[chunks])
#add last one too
consecutive_list.append(data_[chunks + 1])
else:
#yield here and empty list
yield consecutive_list
consecutive_list = []
except Exception:
pass
yield consecutive_list
Test:
#Stephen's list
print(list(chunk_lists_(list(range(0, 11)) +
list(range(80, 91)) +
list(range(160, 171)))))
output:
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90], [160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]]
I have two lists of lists I want to iterate through them and compare the values in each bracket on the list bracket by bracket.....
List_1
[[42, 43, 45, 48, 155, 157], [37, 330, 43, 47, 157], [258, 419, 39, 40, 330, 47], [419, 39, 44, 589, 599, 188].....
List_2
[[37, 330, 43, 47, 157], [258, 419, 39, 40, 330, 47], [419, 39, 44, 589, 599, 188], [41, 44, 526, 602, 379, 188]....
I need to compare the first bracket in List_1 [42, 43, 45, 48, 155, 157]
With the first bracket in List_2 [37, 330, 43, 47, 157]
the desired result is the numbers that are the same in each sequential bracket...for first bracket the result is 43 and 157
then I need to continue second bracket in List_1, with the second bracket in List_2 etc.
Number of values in each bracket may vary
I need each bracket in 1 list to compare with the corresponding bracket from the other list
I don't need the results to be separate
I'm at a very basic level but, I've tried a few different things including using sets intersection, list matches. I'm sure that there is a simple way but only just getting started.
set_x = set([i[1] for i in list_1])
print(set_x)
set_y = set([i[0] for i in list_2])
matches = set_x.intersection(set_y)
print(matches)
this is providing an answer that is way off {3, 8, 396, 12,} and I can't really work out what it's doing.
also tried this
common_elements=[]
import itertools
for i in list(itertools.product(coords_list_1,coords_list_2)):
if i[0] == i[1]:
common_elements.append(i[0])
print(common_elements)
but it produces a mass of results.
Thanks for your help!
Use zip and set's intersection:
for x, y in zip(List_1, List_2):
print(set(x).intersection(y))
# {43, 157}
# {330, 47}
# {419, 39}
# {188, 44}
Your approach tackles the elements in the wrong "axis". For instance:
set_x = set([i[1] for i in list_1])
creates a set of the 2nd element of each list.
In those cases, you have to forget about the indexes.
you just want to zip sublists together to perform intersection between them
List_1 = [[42, 43, 45, 48, 155, 157], [37, 330, 43, 47, 157], [258, 419, 39, 40, 330, 47], [419, 39, 44, 589, 599, 188]]
List_2 = [[37, 330, 43, 47, 157], [258, 419, 39, 40, 330, 47], [419, 39, 44, 589, 599, 188], [41, 44, 526, 602, 379, 188]]
result = [set(x) & set(y) for x,y in zip(List_1,List_2)]
result:
>>> result
[{43, 157}, {330, 47}, {419, 39}, {188, 44}]
Consider a numpy array of the form:
> a = np.random.uniform(0., 100., (10, 1000))
and a list of indexes to elements in that array that I want to keep track of:
> idx_s = [0, 5, 7, 9, 12, 17, 19, 32, 33, 35, 36, 39, 40, 41, 42, 45, 47, 51, 53, 57, 59, 60, 61, 62, 63, 65, 66, 70, 71, 73, 75, 81, 83, 85, 87, 88, 89, 90, 91, 93, 94, 96, 98, 100, 106, 107, 108, 118, 119, 121, 124, 126, 127, 128, 129, 133, 135, 138, 142, 143, 144, 146, 147, 150]
I also have a list of indexes of elements I need to remove from a:
> idx_d = [4, 12, 18, 20, 21, 22, 26, 28, 29, 31, 37, 43, 48, 54, 58, 74, 80, 86, 99, 109, 110, 113, 117, 134, 139, 140, 141, 148, 154, 156, 160, 166, 169, 175, 183, 194, 198, 199, 219, 220, 237, 239, 241, 250]
which I delete with:
> a_d = np.delete(arr, idx_d, axis=1)
But this process alters the indexes of elements in a_d. The indexes in idx_s no longer point in a_d to the same elements in a, since np.delete() moved them. For example: if I delete the element of index 4 from a, then all indexes after 4 in idx_s are now displaced by 1 to the right in a_d.
v Index 5 points to 'f' in a
0 1 2 3 4 5 6
a -> a b c d e f g ... # Remove 4th element 'e' from a
a_d -> a b c d f g h ... # Now index 5 no longer points to 'f' in a_d, but to 'g'
0 1 2 3 4 5 6
How do I update the idx_s list of indexes, so that the same elements that were pointed in a are pointed in a_d?
In the case of an element that is present in idx_s that is also present in idx_d (and thus removed from a and not present in a_d) its index should also be discarded.
You could use np.searchsorted to get the shifts for each element in idx_s and then simply subtract those from idx_s for the new shifted-down values, like so -
idx_s - np.searchsorted(idx_d, idx_s)
If idx_d is not already sorted, we need to feed in a sorted version. Thus, for simplicity assuming these as arrays, we would have -
idx_s = idx_s[~np.in1d(idx_s, idx_d)]
out = idx_s - np.searchsorted(np.sort(idx_d), idx_s)
A sample run to help out getting a better picture -
In [530]: idx_s
Out[530]: array([19, 5, 17, 9, 12, 7, 0])
In [531]: idx_d
Out[531]: array([12, 4, 18])
In [532]: idx_s = idx_s[~np.in1d(idx_s, idx_d)] # Remove matching ones
In [533]: idx_s
Out[533]: array([19, 5, 17, 9, 7, 0])
In [534]: idx_s - np.searchsorted(np.sort(idx_d), idx_s) # Updated idx_s
Out[534]: array([16, 4, 15, 8, 6, 0])
idx_s = [0, 5, 7, 9, 12, 17, 19]
idx_d = [4, 12, 18]
def worker(a, v, i=0):
if not a:
return []
elif not v:
return []
elif a[0] == v[0]:
return worker(a[1:], v[1:], i+1)
elif a[0] < v[0]:
return [a[0]-i] + worker(a[1:], v, i)
else:
return [a[0]-i-1] + worker(a[1:], v[1:], i+1)
worker(idx_s, idx_d)
# [0, 5, 6, 8, 15, 16]
This might be a simple problem but I haven't come up with a solution.
Say I have an array as np.array([0,1,0,1,0,0,0,1,0,1,0,0,1]) with peaks at indexes [1,3,7,9,12]. How can I replace the indexes with [2,8,12], that is, averaging indexes close in distance, if a threshold distance between peaks is set to be greater than 2 in this example?
Please note that the binary values of the array are just for illustration, the peak value can be any real number.
You could use Raymond Hettinger's cluster function:
from __future__ import division
def cluster(data, maxgap):
"""Arrange data into groups where successive elements
differ by no more than *maxgap*
>>> cluster([1, 6, 9, 100, 102, 105, 109, 134, 139], maxgap=10)
[[1, 6, 9], [100, 102, 105, 109], [134, 139]]
>>> cluster([1, 6, 9, 99, 100, 102, 105, 134, 139, 141], maxgap=10)
[[1, 6, 9], [99, 100, 102, 105], [134, 139, 141]]
"""
data.sort()
groups = [[data[0]]]
for item in data[1:]:
val = abs(item - groups[-1][-1])
if val <= maxgap:
groups[-1].append(item)
else:
groups.append([item])
return groups
peaks = [1,3,7,9,12]
print([sum(arr)/len(arr) for arr in cluster(peaks, maxgap=2)])
yields
[2.0, 8.0, 12.0]