I have a list of the form
in_list = [[10, 15], [16,21], [22,25], [26,30], [35,40], [45,50],[51,55]]
And I need to combine consecutive lists that contain consecutive integers in the last and first position into lists. So
if in[1][0] = in[0][1] + 1:
out[0] = [in[0][0],in[1][1]]
The output will be of the form of
out_list = [[10,30], [35, 40], [45,55]]
Right now, the code I have does multiple iterations on the out list and combines the elements, continuing till the number of elements in the list stops changing after an iteration. How can I achieve this in a more pythonic way?
This should do the trick
out = [inp[0]]
for l in inp[1:]:
if l[0] == out[-1][1] + 1:
out[-1][1] = l[1]
else:
out.append(l)
Did you mean one-line stuff using numpy? :)
Try the following shortcut:
import numpy as np
# data is of shape (n,2), n=6
data = np.array([[10, 15], [16,21], [22,25], [26,30], [35,40], [45,50],[51,55]])
# seek for consecutive numbers
marks = (data[:-1,1]+ 1) == data[1:,0]
# re-arrange and return to python lists
output = np.stack([data[:-1,0][marks],data[1:,1][marks]],axis=1).tolist()
EDIT:
Another option using lists:
data = [[10, 15], [16,21], [22,25], [26,30], [35,40], [45,50],[51,55]]
mylist = []
def func(x1,x2):
if x1[1] +1 == x2[0]:
mylist.append((x1[0],x2[1]))
list(map(func,data[:-1],data[1:]))
print(mylist)
Output:
[(10, 21), (16, 25), (22, 30), (45, 55)]
Related
I have the following list:
each pair of the value gives me information about a specific row. I want to be able to compare the values from the first position, to the next and see if the next value is less than the current value, if it is keep it that way, if not delete that pair. So for example, for the first index 0 and 1, comparing 29 to 25, I see that 25 is less than 29 so I keep the pair, now I add two to the current index, taking me to 16 here I see that 16 is not less than 19 so I delete the pair values(16,19). I have the following code:
curr = 0
skip = 0
finapS = []
while curr < len(apS):
if distance1[apS[skip+1]] < distance1[apS[skip]]:
print("its less than prev")
print(curr,skip)
finapS.append(distance1[apS[skip]])
finapS.append(distance1[apS[skip+1]])
skip = skip + 2
curr = curr + 1
print("itterated,", skip, curr)
distance1 is a list of values that has variations of data points. apS is a list that contains the index of the important values from the distance1 list. Distance1 has all the values, but I need only the values from the index of apS, now I need to see if those pairs and the values of them are in descending order. The Code I tried running is giving me infinite loop I can't understand why. Here I am adding the values to a new list, but if possible I would like to just delete those pairs of value and keep the original list.
I think this kind of logic is more easily done using a generator. You can loop through the data and only yield values if they meet your condition. e.g.
def filter_pairs(data):
try:
it = iter(data)
while True:
a, b = next(it), next(it)
if b < a:
yield from (a, b)
except StopIteration:
pass
Example usage:
>>> aps = [1, 2, 3, 1, 2, 4, 6, 5]
>>> finaps = list(filter_pairs(aps))
>>> finaps
[3, 1, 6, 5]
So it looks like you want a new list. Therefore:
apS = [29.12, 25.01, 16.39, 19.49, 14.24, 12.06]
apS_new = []
for x, y in zip(apS[::2], apS[1::2]):
if x > y:
apS_new.extend([x, y])
print(apS_new)
Output:
[29.12, 25.01, 14.24, 12.06]
Pure Python speaking, I think zip is the elegant way of doing this, combined with slice steps.
Assuming you list as defined as::
>>> a = [29, 25, 16, 19, 14, 12, 22, 8, 26, 25, 26]
You can zip the list into itself with a shift of one, and a slice step of two::
>>> list(zip(a[:-1:2], a[1::2]))
[(29, 25), (16, 19), (14, 12), (22, 8), (26, 25)]
Once you have that, you can then filter the sequence down to the items you want, your full solution will be::
>>> list((x, y) for (x, y) in zip(a[:-1:2], a[1::2]) if x > y)
[(29, 25), (14, 12), (22, 8), (26, 25)]
If you prefer to go the numpy path, then read about the np.shift function.
If your test is false you loop without augmenting the counter curr.
You need an
else:
curr+=1
(or +=2 according to the logic)
to progress through the list.
I have a really big list of lists with integers that is also sorted from low to high. Also every nested list is an arithmetic sequence increasing by 1 . To make it more clear it could look something like:
f = [[0,1], [3], [7,8,9,10,11,12], [15,16], [18], [22,23,24], [39,40,41], [49,50,51]]
My goal is to split the nested big list into smaller nested lists. My first list must have numbers between 0 and 10, my second list must have numbers between 20 and 30 , my third between 40 to 50 etc. So I was wondering if there is a way to code in python to get the following lists:
f1 = [[0,1],[3],[7,8,9,10]]
f2 = [[22,23,24]]
f3 = [[40,41],[49,50]]
Here is one way to do so:
data = []
for i in range(0, f[-1][-1], 20):
new_seqs = []
for seq in f:
if i - len(seq) + 1 <= seq[0] <= i + 10:
new_nums = []
for num in seq:
if i <= num <= i + 10:
new_nums.append(num)
new_seqs.append(new_nums)
data.append(new_seqs)
print(data)
The same using list comprehension:
data = [[[num for num in seq if i <= num <= i + 10] for seq in f if i - len(seq) + 1 <= seq[0] <= i + 10] for i in range(0, f[-1][-1], 20)]
print(data)
Output:
[[[0, 1], [3], [7, 8, 9, 10]], [[22, 23, 24]], [[40, 41], [49, 50]]]
We run a for loop from 0 to the largest element in the list (f[-1][-1]), increasing by 20 each time.
For each sub-list we check if at least one element is included between i and i + 10. As it is an arithmetic sequence of common difference 1, we only have to compare the first term.
If there is at least one term in the interval, we compare each number with i and i + 10.
I guess, similar to this is what you are looking for?
from collections import defaultdict
mem = defaultdict(list)
# expectations: each sub-list is stickly between x * 10 and (x+1) * 10 where x is a number
def find_list_number(num, i=10):
if num < i:
return int(i / 10)
else:
return find_list_number(num, i + 10)
for sub_list in flist:
my_max = max(sub_list)
key = find_list_number(my_max)
mem[key].append(sub_list)
for k, v in mem.items():
print((k, v))
Sample Output for above
(1, [[0, 1], [3]])
(2, [[7, 8, 9, 10, 11, 12], [15, 16], [18]])
(3, [[22, 23, 24]])
(5, [[39, 40, 41]])
(6, [[49, 50, 51]])
Note: [7,8,9,10,11,12] is in different class - not bug here. But you can modify conditions as you need & add additional conditions as it suits you. This is a sample, only to guide you.
for n in range(1,(len(randnum))/3):
X.append(randnum(n))
for i in range((len(randnum))/3 , (2/3)*len(randnum)):
Y.append(randnum(i))
for r in range ((2/3)*len(randnum) , len(randnum)):
Z.append(randnum(r))
I have been trying to form a list based on this criteria and I keep getting this error message for specifically this line below:
for n in range(1,(len(randnum))/3):
TypeError: 'float' object cannot be interpreted as an integer
The part of the program that is causing the problems is that part above and if I can fix it I can take the error and apply it to the rest.
Here is an example list that is used to fill the other three it has 20 elements and I want each list that I form to take from this list about 1/3 of its elements from different positions:
[ 59.18013391 12159.7881626 26308.21887981 8357.05103068
20718.85232457 16333.1546026 9828.75690047 10273.65018539
5949.58907673 8767.68292925 31826.29595355 13749.12915211
25423.61181129 28799.50849876 9517.54482827 27275.19296144
12460.2541769 25883.7888204 10393.9452616 26008.572598 ]
And I want this code to form 3 new lists containing in for example
X = [59.18013391 12159.7881626 26308.21887981 8357.05103068
20718.85232457 16333.1546026]
Y = [9828.75690047 10273.65018539
5949.58907673 8767.68292925 31826.29595355 13749.12915211 ]
Z = [ 25423.61181129 28799.50849876 9517.54482827 27275.19296144
12460.2541769 25883.7888204 10393.9452616 26008.572598]
You cannot use float for the range() function.
See: https://docs.python.org/3/library/stdtypes.html#range
(len(randnum))/3
that's float!
possible fix :
int((len(randnum))/3)
OKAY, perhaps your should try random
With repetition
import random
original_list =[ i for i in range(20)]
X = random.sample(original_list, int(len(original_list)/3))
Y = random.sample(original_list, int(len(original_list)/3))
Z = random.sample(original_list, int(len(original_list)/3))
Sample Output
X: [7, 3, 18, 15, 19, 1]
Y : [6, 13, 17, 4, 14, 5]
Z: [19, 2, 8, 18, 13, 17]
Without repetition
from random import shuffle
shuffle(original_list)
list(zip(*[iter(original_list)]*int(len(original_list)/3)))
Sample Output
[(17, 13, 15, 5, 16, 12), (14, 4, 18, 2, 19, 6), (10, 11, 7, 3, 1, 0)]
If I follow your goal, a simple approach would be to shuffle a copy of the list and then take every 3rd element starting at 0, then 1, then 2:
tmp_data = data.copy()
random.shuffle(tmp_data)
new_lists = [tmp_data[i::3] for i in range(3)]
which gives me, e.g.
In [361]: new_lists
Out[361]:
[[13749.12915211,
26008.572598,
25423.61181129,
8767.68292925,
12460.2541769,
26308.21887981,
59.18013391],
[9828.75690047,
20718.85232457,
10273.65018539,
9517.54482827,
27275.19296144,
8357.05103068,
5949.58907673],
[28799.50849876,
12159.7881626,
25883.7888204,
16333.1546026,
10393.9452616,
31826.29595355]]
and you could then do
X, Y, Z = new_lists
if you insisted on separate named variables.
(You could also simply do tmp_data = random.sample(data, len(data)) to get a random permutation of the list instead, but for some reason I find this less clear than shuffling. Not sure why.)
You could use random here but also you are going to need to make sure you don't use that random int again, my approach is append it to a used list and check that list to see if it can be used again, as far as splitting them you have 20 so you can use // floor division and % to help you create two lists of 7 items and one of 6 items.
import random
data = [
59.18013391,12159.7881626,26308.21887981, 8357.05103068,
20718.85232457,16333.1546026,9828.75690047, 10273.65018539,
5949.58907673, 8767.68292925, 31826.29595355, 13749.12915211,
25423.61181129, 28799.50849876, 9517.54482827, 27275.19296144,
12460.2541769, 25883.7888204, 10393.9452616, 26008.572598
]
y = len(data)//3
z = int((len(data) % 3)/2)
used = []
l1 = []
l2 = []
l3 = []
for i in range(y):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l1.append(data[x])
for i in range(y+z):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l2.append(data[x])
for i in range(y+z):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l3.append(data[x])
chrx#chrx:~/python/stackoverflow/9.23$ python3.7 loop.py
l1: [8357.05103068, 10273.65018539, 26008.572598, 5949.58907673, 28799.50849876, 8767.68292925]
l2: [25423.61181129, 13749.12915211, 26308.21887981, 9828.75690047, 59.18013391, 16333.1546026, 27275.19296144]
l3: [12460.2541769, 12159.7881626, 9517.54482827, 10393.9452616, 25883.7888204, 31826.29595355, 20718.85232457]
I have a large array of integers, and I need to print the maximum of every 10 integers and its corresponding index in the array as a pair.
ex. (max_value, index of max_value in array)
I can successfully find the maximum value and the corresponding index within the first 10 integers, however I am having trouble looping through the entire array.
I have tried using:
a = some array of integers
split = [a[i:i+10] for i in xrange(0, len(a), 10)]
for i in split:
j = max(i)
k = i.index(max(i))
print (j,k)
The issue with this method is that it splits my array into chunks of 10 so the max_values are correct, but the indexes are inaccurate (all of the indexes are between 0-10.)
I need to find a way of doing this that doesn't split my array into chunks so that the original indices are retained. I'm sure there is an easier way of looping through to find max values but I can't seem to figure it out.
A small modification to your current code:
a = some array of integers
split = [a[i:i+10] for i in xrange(0, len(a), 10)]
for index, i in enumerate(split):
j = max(i)
k = i.index(max(i))
print (j, k+10*index)
You need to count the number of elements that appear before the current window. This will do the job:
a=list(range(5,35))
split = [a[i:i+10] for i in xrange(0, len(a), 10)]
for ind,i in enumerate(split):
j = max(i)
k = i.index(j)
print (j,k+ind*10)
This prints
(14, 9)
(24, 19)
(34, 29)
So with debugging with an example array, we find that split returns a 2d list like this one:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]]
And every time the for loop runs, it does through one of those lists in order. First it goes through the first inner list then the second one etc. So every time the for loop jumps into the next list, we simply add 10. Since the list can have over 2 lists in them, we store the number we need to add in a variable and add 10 to it every loop:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
split = [a[i:i+10] for i in xrange(0, len(a), 10)]
counter = 0
for i in split:
j = max(i)
k = i.index(max(i))
print (j,k+counter)
counter += 10
You can test it here
The toolz package has a partition_all function that divides a sequence up into equal-sized tuples, so you can do something like this.
import toolz
ns = list(range(25))
[max(sublist) for sublist in toolz.partition_all(10, ns)]
This will return [9, 19, 24].
You will need to loop through in order to iterate through the list, however we could change your split's loop to make it more effective to what you want.
a = some array of integers
split = [a[i:i+10] for i in xrange(0, len(a), 10)]
for i in range(len(split)):
#Now instead of being the list, i is the index, so we can use 10*i as a counter
j = max(split[i])
#j = max(i)
k = split[i].index(j) + 10*i #replaced max(i) with j since we already calculated it.
#k = i.index(max(i))
print (j,k)
Though in the future, please make a new name for your split list since split is already a function in python. Perhaps split_list or separated or some other name that doesn't look like the split() function.
numpy solution for arbitrary input:
import numpy as np
a = np.random.randint(1,21,40) #40 random numbers from 1 to 20
b = a.reshape([4,10]) #shape into chunks 10 numbers long
i = b.argsort()[:,-1] #take the index of the largest number (last number from argsort)
# from each chunk. (these don't take into account the reshape)
i += np.arange(0,40,10) #add back in index offsets due to reshape
out = zip(i, a[i]) #zip together indices and values
You could simplify this by only enumerating once and using zip to partition your list into groups:
n=10
for grp in zip(*[iter(enumerate(some_list))]*n):
grp_max_ind, grp_mv=max(grp, key=lambda t: t[1])
k=[t[1] for t in grp].index(grp_mv)
print grp_mv, (grp_max_ind, k)
Use izip in Python 2 if you want a generator (or use Python 3)
from itertools import izip
for grp in izip(*[iter(enumerate(some_list))]*n):
grp_max_ind, grp_mv=max(grp, key=lambda t: t[1])
k=[t[1] for t in grp].index(grp_mv)
print grp_mv, (grp_max_ind, k)
Zip will truncate the last group if not a length of n
An example using numpy. First let's generate some data, i.e., integers ranging from 1 to V and of length (number of values) L:
import numpy as np
V = 1000
L = 45 # method works with arrays not multiples of 10
a = np.random.randint(1, V, size=L)
Now solve the problem for sub-arrays of size N:
import numpy as np
N = 10 # example "split" size
sa = np.array_split(a, range(N, len(a), N))
sind = [np.argpartition(i, -1)[-1] for i in sa]
ind = [np.ravel_multi_index(i, (len(sa), N)) for i in enumerate(sind)]
vals = np.asarray(a)[np.asarray(ind)]
split_imax = zip(vals, ind) # <-- output
Given a list of numbers, I am trying to write a code that finds the difference between consecutive elements. For instance, A = [1, 10, 100, 50, 40] so the output of the function should be [0, 9, 90, 50, 10]. Here is what I have so far trying to use recursion:
def deviation(A):
if len(A) < 2:
return
else:
return [abs(A[0]-A[1])] + [deviation(A[1: ])]
The output I get, however, (using the above example of A as the input) is [9, [90, [50, [10, None]]]]. How do I properly format my brackets? (I've tried guessing and checking but I this is the closest I have gotten) And how do I write this where it subtracts the current element from the previous element without getting an index error for the first element? I still want the first element of the output list to be zero but I do not know how to go about this using recursion and for some reason that seems the best route to me.
You can do:
[y-x for x, y in zip(A[:-1], A[1:])]
>>> A = [1, 10, 100, 50, 40]
>>> [y-x for x, y in zip(A[:-1], A[1:])]
[9, 90, -50, -10]
Note that the difference will be negative if the right side is smaller, you can easily fix this (If you consider this wrong), I'll leave the solution for you.
Explanation:
The best explanation you can get is simply printing each part of the list comprehension.
A[:-1] returns the list without the last element: [1, 10, 100, 50]
A[1:] returns the list without the first element: [10, 100, 50, 40]
zip(A[:-1], A[1:]) returns [(1, 10), (10, 100), (100, 50), (50, 40)]
The last step is simply returning the difference in each tuple.
The simplest (laziest) solution is to use the numpy function diff:
>>> A = [1, 10, 100, 50, 40]
>>> np.diff(A)
array([ 9, 90, -50, -10])
If you want the absolute value of the differences (as you've implied by your question), then take the absolute value of the array.
[abs(j-A[i+1]) for i,j in enumerate(A[:-1])]
You can do a list comprehension:
>>> A = [1, 10, 100, 50, 40]
>>> l=[A[0]]+A
>>> [abs(l[i-1]-l[i]) for i in range(1,len(l))]
[0, 9, 90, 50, 10]
For a longer recursive solution more in line with your original approach:
def deviation(A) :
if len(A) < 2 :
return []
else :
return [abs(A[0]-A[1])] + deviation(A[1:])
Your bracket issue is with your recursive call. Since you have your [deviation(a[1: ])] in its own [] brackets, with every recursive call you're going to be creating a new list, resulting in your many lists within lists.
In order to fix the None issue, just change your base case to an empty list []. Now your function will add 'nothing' to the end of your recursively made list, as opposed to the inherent None that comes with a blank return'
Actually recursion is an overkill:
def deviation(A):
yield 0
for i in range(len(A) - 1):
yield abs(A[i+1] - A[i])
Example:
>>> A = [3, 5, 2]
>>> list(deviation(A))
[0, 2, 3]
EDIT: Yet, another, even simplier and more efficient solution would be this:
def deviation(A):
prev = A[0]
for el in A:
yield abs(el - prev)
prev = el