Turn 1D list to a triangle 2D list - python

I have a list made of range from 1 to 55 with step 2: [1, 3, 5, 7, 9, 11, 13, 15, ..., 53].
What I'm trying to do is to fill another list, which is 2D and triangular, with numbers from the first list.
def odd_triangle(n):
a = []
b = []
for number in range(1, 55, 2):
a.append(number)
for i in range(n):
b.append([])
for j in range(i+1):
b[i].append(a[i])
print(b)
After I call that function, for example odd_triangle(5) (5 rows will be created), it gives me not exactly what I want to:
[[1], [3, 3], [5, 5, 5], [7, 7, 7, 7], [9, 9, 9, 9, 9]]
What I want it to be is: [[1], [3, 5], [7, 9, 11], [13, 15, 17, 19], [21, 23, 25, 27, 29]]

This will work:
a = list(range(1,55,2))
n = 5
it = iter(a)
b = list([next(it) for _ in range(i)] for i in range(1, n+1))
Gives:
[[1], [3, 5], [7, 9, 11], [13, 15, 17, 19], [21, 23, 25, 27, 29]]
Here, next(it) simply gets the next value from the iterator over a every time it is called.

Related

How do I put data in a two-dimensional array sequentially without duplication?

I want to put data consisting of a one-dimensional array into a two-dimensional array. I will assume that the number of rows and columns is 5.
The code I tried is as follows.
data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a = []
for i in range(5):
a.append([])
for j in range(5):
a[i].append(j)
print(a)
# result : [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
# I want this : [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20]]
You don't have to worry about the last [20].
The important thing is that the row must change without duplicating the data.
I want to solve it, but I can't think of any way. I ask for your help.
There are two issues with the current code.
It doesn't actually use any of the values from the variable data.
The data does not contain enough items to populate a 5x5 array.
After adding 0 to the beginning of the variable data and using the values from the variable, the code becomes
data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a = []
for i in range(5):
a.append([])
for j in range(5):
if i*5+j >= len(data):
break
a[i].append(data[i*5+j])
print(a)
The output of the new code will be
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20]]
This should deliever the desired output
data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a = []
x_i = 5
x_j = 5
for i in range(x_i):
a.append([])
for j in range(x_j):
a[i].append(i*x_j+j)
print(a)
Output:
[[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]]
By using list comprehension...
data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
columns = 5
rows = 5
result = [data[i * columns: (i + 1) * columns] for i in range(rows)]
print(result)
# [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20]]
You could use itertools.groupby with an integer division to create the groups
from itertools import groupby
data = [0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
grouped_data = [list(v) for k, v in groupby(data, key=lambda x: x//5)]
print(grouped_data)
Output
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20]]

Sorting multidimensional array in python

Let say I have an array of
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
I want to sort the value so that it will look like this:
x = [[0, 5, 5, 5, 7, 7], [8, 9, 10, 10, 13, 16], [17, 17, 35]]
How could I achieve this?
code:
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
y = sorted(sum([i for i in x],[]))
result = []
for i in x:
temp = []
for j in range(len(i)):
temp.append(y.pop(0))
result.append(temp)
print(result)
result:
[[0, 5, 5, 5, 7, 7], [8, 9, 10, 10, 13, 16], [17, 17, 35]]
The best answer is given by #leaf_yakitori please look at it. Now I just added this code to reduce time complexity from O(n^2) to O(n)
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
y = sorted(sum([i for i in x],[]))
result = []
ind = 0
for i in x:
result.append(y[ind:ind + len(i)])
ind += len(i)
print(result)

Splitting list based on difference between consecutive elements

I found this question that is related to mine. In that question a specific case is treated, and that's splitting a list of integers when a difference of more than 1 is present between consecutive elements.
I was wondering: is there way to make this work for a difference of N, a parameter? Namely, suppose we have this list:
[1,2,3,6,8,10,14,15,17,20]
For N=2, the output should be:
[[1,2,3], [6,8,10], [14,15,17], [20]]
For N=3, the output should be:
[[1,2,3,6,8,10], [14,15,17,20]]
And for N=4, the output should be the same input list.
I did it like this:
from itertools import takewhile
input_list = [1,2,3,6,8,10,14,15,17,20]
N = 4
def fun(l, N, output=[]):
if len(l):
output.append([x[1] for x in takewhile(lambda x: x[1]-x[0]<=N,
zip([l[0]]+l, l))])
fun(l[len(output[-1]):], N, output)
return output
fun(input_list, N)
But I don't really like it: it's unreadable. Something stylish as a one-liner or something pretty pythonic would be appreciated!
Two lines with list-comprehension:
def split_list(l, n):
index_list = [None] + [i for i in range(1, len(l)) if l[i] - l[i - 1] > n] + [None]
return [l[index_list[j - 1]:index_list[j]] for j in range(1, len(index_list))]
test:
example = [1, 2, 3, 6, 8, 10, 14, 15, 17, 20]
for i in range(2,5):
print(split_list(example, i))
# [[1, 2, 3], [6, 8, 10], [14, 15, 17], [20]]
# [[1, 2, 3, 6, 8, 10], [14, 15, 17, 20]]
# [[1, 2, 3, 6, 8, 10, 14, 15, 17, 20]]
def spacer(data, n=1):
set(data)
output = [[data[0]]]
for i in data[1:]:
if i - output[-1][-1] > n:
output.append([i])
else:
output[-1].append(i)
return output
data = [1, 2, 3, 6, 8, 10, 14, 15, 17, 20]
for i in range(1, 4):
print("N={}, {}".format(i, spacer(data, n=i)))
output:
N=1, [[1, 2, 3], [6], [8], [10], [14, 15], [17], [20]]
N=2, [[1, 2, 3], [6, 8, 10], [14, 15, 17], [20]]
N=3, [[1, 2, 3, 6, 8, 10], [14, 15, 17, 20]]

Split list at a specific value

I am trying to write a code that splits lists in a class of lists in two when a certain value is a middle element of the list and then produce two lists where the middle element becomes the end element in the first list and the first element in the second one.
There can be more than n middle elements in the list so the result must be n+1 lists.
Example:
A = [[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]]
P = [4,7,13,20]
n = len(Points) # in this case n = 4
I am looking for a result that looks like this:
A = [[0,1,2,3,4],[4,5,6,7],[7,8,9,10,11,12,13],[13,14,15],[16,17,18,19,20],[20,21,22,23,24,25],[26,27,28,29]]
Since n = 4 and it will produce 5 lists, note that the answer has 6 lists because the last list doesn't have any value of P in and therefore stays intact.
I haven't been able to produce anything as I am new to python and it is hard to formulate this problem.
Any help is appreciated!
You can first recover all indices of the provided values and then slice accordingly.
Code
def split_at_values(lst, values):
indices = [i for i, x in enumerate(lst) if x in values]
for start, end in zip([0, *indices], [*indices, len(lst)]):
yield lst[start:end+1]
# Note: remove +1 for separator to only appear in right side slice
Example
values = {4, 7, 13, 20}
lst = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
print(*split_at_values(lst, values))
Output
[0, 1, 2, 3, 4] [4, 5, 6, 7] [7, 8, 9, 10, 11, 12, 13] [13, 14, 15]
You can then apply this iteratively to you input list A to get the desired result. Alternatively you can use itertools.chain.from_iterable.
from itertools import chain
values = {4, 7, 13, 20}
lst_A = [[0, 1, 2, 3, 4, 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]]
output = list(chain.from_iterable(split_at_values(sublst, values) for sublst in lst_A))
print(output)
Output
[[0, 1, 2, 3, 4],
[4, 5, 6, 7],
[7, 8, 9, 10, 11, 12, 13],
[13, 14, 15],
[16, 17, 18, 19, 20],
[20, 21, 22, 23, 24, 25],
[26, 27, 28, 29]]
You can keep appending the sub-list items to the last sub-list of the output list, and if the current item is equal to the next item in Points, append a new sub-list to the output with the same item and pop the item from Points:
output = []
for l in List:
output.append([])
for i in l:
output[-1].append(i)
if Points and i == Points[0]:
output.append([i])
Points.pop(0)
With your sample input, output would become:
[[0, 1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10, 11, 12, 13], [13, 14, 15], [16, 17, 18, 19, 20], [20, 21, 22, 23, 24, 25], [26, 27, 28, 29]]

Efficient way to find index of elements in a large list of integers starting with max to min elements

I have a large list of integers unsorted, numbers might be duplicated. I would like to create another list which is a list of sub-lists of indexes from the first list starting with max element to min, in decreasing order.
For example, if I have a list like this:
list = [4, 1, 4, 8, 5, 13, 2, 4, 3, 7, 14, 4, 4, 9, 12, 1, 6, 14, 10, 8, 6, 4, 11, 1, 2, 11, 3, 9]
The output should be:
indexList = [[10, 17], [5], [14], [22, 25], [18], [13, 27], [3, 19], [9], [16, 20], [4], [0, 2, 7, 11, 12, 21], [8, 26], [6, 24], [1, 15, 23]]
where, [10, 17] is the index of where '14' is present and so on...
Shared my code below. Profiling it using cProfile for a list of around 9000 elements takes around ~6 seconds.
def indexList(list):
# List with sorted elements
sortedList = sorted(list, reverse = True)
seen = set()
uSortedList = [x for x in sortedList if x not in seen and not seen.add(x)]
indexList = []
for e in uSortedList:
indexList.append([i for i, j in enumerate(list) if j == e])
return indexList
Here you go:
def get_list_indices(ls):
indices = {}
for n, i in enumerate(ls):
try:
indices[i].append(n)
except KeyError:
indices[i] = [n]
return [i[1] for i in sorted(indices.items(), reverse=True)]
test_list = [4, 1, 4, 8, 5, 13, 2, 4, 3, 7, 14, 4, 4, 9, 12, 1, 6, 14, 10, 8, 6, 4, 11, 1, 2, 11, 3, 9]
print(get_list_indices(test_list))
Based on some very basic testing, it is about twice as fast as the code you posted.

Categories