I'm trying to split a list to 5 lists. I searched on internet but the only thing I could find was how to split a list to n number of list, with the same amount of items in every list.
This sadly doesn't solve my problem. What I want to do is split a list into 5 lists with different amounts of items.
Lets say the list has 35 items, (this is not always 35, but it is
never more then 45).
I want to split it into:
a list containing items 1-5
a list containing items 5-13
a list containing items 13-20
a list containing items 20-27
and a list containing items 27-35
All of the things I saw where aimed at splitting a list into sub-lists of same sizes. So I was wondering if this is even possible.
You can achieve this using basic list slicing, like below:
In [1]: l = list(xrange(35))
In [2]: l[0:5], l[5:13], l[13:20], l[20:27], l[27:35]
Out[2]:
([0, 1, 2, 3, 4],
[5, 6, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26],
[27, 28, 29, 30, 31, 32, 33, 34])
I couldn't find any repeatable pattern between the numbers 1, 5, 13, 20, 27, 35, but if there is one, you can easily calculate the nth and n+1th terms, to get the slices dynamically instead of hardcoding.
Also note, the indexes begin with 0 for a list in Python, and that when a slice of list[x:y] is done, the elements list[x], list[x+1], .. list[y-1] only are contained in the slice, and list[y] is not the part of final output.
Related
Community of stackoverflow:
I have a list "rest" which is the following:
rest=[5, 7, 11, 4]
I have another list which is b:
b=[21, 22, 33, 31, 23, 15, 19, 13, 6]
And I have a "last" list:
last=[33, 19, 40, 21, 31, 22, 6, 15, 13, 23]
I have to replace the first 4 elements in b with the elements in rest. How can I replace the elements in last according to the matches with b to get the rest elements?
for example:
5 7 11 4 #elements from rest
b= [21, 22, 33, 31, 23, 15, 19, 13, 6]
to get last list as the following:
last=[11, 19, 40, 5, 4, 7, 6, 15, 13, 23] #elements that matched with b were replaced by rest
How can I do this?
Try this:
rest=[5, 7, 11, 4]
b=[21, 22, 33, 31, 23, 15, 19, 13, 6]
last=[33, 19, 40, 21, 31, 22, 6, 15, 13, 23]
for i, l in enumerate(last):
if l in b:
if b.index(l) < len(rest):
last[i] = rest[b.index(l)]
print(last)
You can try to do something like this...
rest_change_index = 0
for i in range(len(b)):
if b[i] in last:
last_change_index = last.index(b[i])
last[last_change_index] = rest[rest_change_index]
rest_change_index += 1
print(last)
This iterates through the elements of b, and if an element in last matches the element of b being iterated through in the loop, then it changes that value with the corresponding element of rest (first element of rest for first matching instance, etc.). Let me know if this makes sense.
You can do this as follows:
# Get first 4 items in b
b4 = b[:4]
# Create mapping from b to rest
b_to_rest = dict(zip(b4, rest))
# Use dictionary .get to either replace if in rest or keep if not
last = [b_to_rest.get(x,x) for x in last]
Firstly, I've defined b4 as the first 4 items in b. Then I've used zip and dict to map b values to rest values. Finally I use a list comprehension to replace the items in last. .get(x,x) means try to get x from the dictionary, if it doesn't exist just use x.
I am able to generate the desired output but i need 10 of them and each list has to be unicue. The best solution i thought of was to create a 2nd function, generate a emty list and populate each element with list from 1st function. The output i got so far is x amount of lists but they are not unique and python gives me error when i try to call on the first function inside the 2nd one.
import random
numbers = list(range(1, 35))
out = []
final = []
print(numbers) # to see all numbers
# returns 7 unique pop'd numbers from list 'numbers' and appends them to list 'out'
def do():
for x in range(7):
out.append(numbers.pop(random.randrange(len(numbers))))
print(sorted(out))
# In other words i want to print output from function do() 10 times but each item in list has to be unique, not the lists themself
def do_ten():
for x in range(10):
final.append(out)
# do() python doesnt like this call
print(sorted(final))
do_ten()
This generates a specific amount of lists, in a list, which contain random numbers from 1 to 100, you can use l and n to control the amount of lists and numbers respectively.
import random
l, n = 3, 5 # The amount of lists and numbers respectively.
lis = [[i for i in random.sample(range(1, 35), n)] for group in range(l)]
print(lis)
Random Output:
[[16, 11, 17, 13, 9], [26, 6, 16, 29, 24], [24, 2, 4, 1, 20]]
You are popping 10 times 7 numbers from a list containing 34 elements (from 1 to 34). This is not possible. You need to have at least 70 elements in your list numbers(for example, from 0 to 69).
This is a solution that should work, based on the code you've already written:
import random
numbers = list(range(0, 70))
final = []
print(numbers) # to see all numbers
# returns a list of 7 unique popped numbers from list 'numbers'
def do():
out = []
for x in range(7):
l = len(numbers)
r = random.randrange(l)
t = numbers.pop(r)
out.append(t)
return out
# Call 10 times do() and add the returned list to 'final'
def do_ten():
for x in range(10):
out = do() # Get result from do()
final.append(out) # Add it to 'final'
do_ten()
print(final)
Does it help:
num_lists = 10
len_list = 10
[list(np.random.randint(1,11,len_list)) for _ in range(num_lists)]
As some people may have different definitin of "uniqueness", you may try:
source_list = range(0, num_lists*len_list,1)
[list(np.random.choice(source_list, len_list, replace=False)) for _ in range(num_lists)]
Pulling 7 of 34 numbers from your numberrange without repeats can be done using random.sample - to ensure you do not get duplicate lists, you can add a tuple of the list to a set and your final result and only add to final if this tuple is not yet in the set:
import random
numbers = range(1, 35) # 1...34
final = []
chosen = set()
while len(final) < 10:
# replace popping numbers with random.sample
one_list = random.sample(numbers, k=7) # 7 numbers out of 34 - no repeats
# create a tuple of this list and only add to final if not yet added
t = tuple(one_list)
if t not in chosen:
chosen.add(t)
final.append(one_list)
print (final)
Output:
[[1, 5, 10, 26, 14, 33, 6],
[3, 11, 1, 30, 7, 21, 18],
[24, 23, 28, 2, 13, 18, 1],
[4, 25, 32, 15, 22, 8, 27],
[32, 9, 10, 16, 17, 26, 12],
[34, 32, 10, 26, 16, 21, 20],
[6, 34, 22, 11, 26, 12, 5],
[29, 17, 25, 15, 3, 6, 5],
[24, 8, 31, 28, 17, 12, 15],
[6, 19, 11, 22, 30, 33, 15]]
If you dont need unique resulting lists, you can simplify this to a one-liner but it might have dupes inside:
final = [random.sample(range(1,11),k=7) for _ in range(10)]
This works fine for my purposes, except that when the value (in this case 20) is the same, it will only return the index from the front. Code is as follows, I'm not sure what the workaround is, but I need it to return the index of the value from reversed. I have some floats that would differ, but seem more difficult to work with.
lmt_lst = [-1, 5, 9, 20, 44, 37, 22, 20, 17, 12, 6, 1, -6]
lft_lmt = next(x for x in lmt_lst if x >=20)
rgt_lmt = next(x for x in reversed(lmt_lst) if x >= 20)
lft_idx = lmt_lst.index(lft_lmt)
rgt_lmt = lmt_lst.index(rgt_lmt)
print('Left Limit:', lft_lmt, 'Left Index:', lft_idx)
print('Right Limit:', rgt_lmt, 'Right Index:', rgt_idx)
If you change either of the values of '20' to 21, it works just fine
It does not return any errors, just returns the first index of the value, regardless of reversed
Your lft_lmt and rgt_lmt lists only contain values greater than or equal to 20, so your lists are [20, 44, 37, 22, 20] and [20, 22, 37, 44, 20] respectively.
>>> lmt_lst = [-1, 5, 9, 20, 44, 37, 22, 20, 17, 12, 6, 1, -6]
>>> [x for x in lmt_lst if x >=20]
[20, 44, 37, 22, 20]
>>> [x for x in reversed(lmt_lst) if x >= 20]
[20, 22, 37, 44, 20]
The first item of both of these lists is 20, and so when you search for them (using .index which searches from the beginning of the list) in the initial list you'll get 3 both times (because 20 is found at position 3 no matter how many times you search the list from beginning to end).
To find your right index you want to search the reversed list and account for the result being as if searching the list backwards:
>>> lft_idx = lmt_lst.index(lft_lmt)
>>> lft_idx
3
>>> rgt_idx = len(lmt_lst) - 1 - lmt_lst[::-1].index(rgt_lmt)
>>> rgt_idx
7
Let say this is the original list
a = [['john', 12, 15],
['keith', 8, 20],
['jane', 18, 10]]
I want to add a value 99 to each row, the expected result will be like
a = [['john', 12, 15, 99],
['keith', 8, 20, 99],
['jane', 18, 10, 99]]
Any build in function to achieve this result?
If you want to modify your existing lists then simply loop and append:
for l in a:
l.append(99)
If you are fine with creating new lists then use the list-comprehension suggested by #languitar.
You can use list comprehension for this:
a = [x + [99] for x in a]
Btw. what you are using is a python list, not an array.
Could any one explain me how does the command (<---) below works in python numpy
r = np.arange(36)
r.resize(6,6)
r.reshape(36)[::7] # <---
You just have to run the commands one by one and analyse their output:
Create a list of the first [0, 35] numbers.
>>> r = np.arange(36)
>>> r
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35])
Reshape the list in-place to a 6 x 6 array:
>>> r.resize(6,6) # equivalent to r = r.reshape(6,6)
>>> r
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]])
Reshape the vector r to a 1Dimensional vector
>>> tmp = r.reshape(36)
tmp above is exactly the same as r in the first step
Filter every 7 element
>>> tmp[::7]
array([ 0, 7, 14, 21, 28, 35])
Slicing/Indexing is represented as i:j:k, where i = from, j = to and k = step. Thus, 5:10:2 would mean from element 5th to the 10th, give me elements every 2 steps. If i is not present, it is assumed to be from the beginning of the array. If j is not present, it is assumed to be until the end of the array. If k is not present it is assumed to have an step of 1 (all the elements in the range).
With all the above, you could rewrite your example in a single line as:
>>> np.arange(36)[::7]
Or if you already have r, which is N-Dimensional:
>>> r.ravel()[::7]
Here ravel will return a 1Dimensional view of r (preferred to reshape(36)).
If you want to know more about slicing, please refer to the numpy documentation.
At first, you are using NumPy ndarray.reshape, which reconstructs the given array to the specified shape. In your case, you are converting it to a 1-Dimension array with 36 elements.
Secondly, with the numbers between brackets, your are indexing certain values in the array. The slicing consists in 3 values per dimension, in the form of [number1:number2:number3]. If you leave the values blank (like in your case for numbers 1 and 2), you will leave them to default i.e. number1 will be 0, number2 will be -1 (the last array index) and number3 will be 3:
The first number indicates the array index where you will begin taking values.
The second number indicates the array index where you will stop taking values.
Finally, the last number indicates the number of positions that will be ignored after each index reading. In your case, you are reading every 7 indexes.
One point to add, both reshape() and resize() methods have the SAME functionality, the ONLY difference between them is how they affect the calling array object r:
r.resize() have no return. It directly change the shape of calling array object r.
r.reshape() returns a new reshaped array object. And leaves the original r unchanged.
>>> import numpy as np
>>> r = np.arange(36)
>>> r.shape
(36,)
>>> # 1. --- `reshape()` returns a new object and keep the `r` ---
>>> new = r.reshape(6,6)
>>> new.shape
(6, 6)
>>>
>>> # 2. --- resize changes `r` directly and returns `None` ---
>>> nothing = r.resize(6,6)
>>> type(nothing)
<class 'NoneType'>
>>> r.shape
(6, 6)