2016-08-09 24 views
12

Tôi biết cách chia danh sách thành các nhóm thậm chí, nhưng tôi đang gặp sự cố khi chia nhỏ danh sách thành các nhóm không đồng đều.Tách danh sách thành các nhóm không đồng đều?

Về cơ bản đây là những gì tôi có: một số danh sách, hãy gọi nó là mylist, có chứa các phần tử x.

Tôi cũng có một tập tin, cho phép gọi nó là second_list, mà trông giống như sau:

{2, 4, 5, 9, etc.} 

Bây giờ những gì tôi muốn làm là chia mylist thành các nhóm không đồng đều bởi khoảng cách trong second_list. Vì vậy, tôi muốn nhóm đầu tiên của tôi là 2 phần tử đầu tiên của mylist, nhóm thứ hai là 4 phần tử tiếp theo của mylist, nhóm thứ ba là 5 phần tử tiếp theo của mylist, nhóm thứ tư là 9 phần tử tiếp theo của `danh sách của tôi, v.v.

Có cách nào dễ dàng để thực hiện việc này không? Tôi đã thử làm một điều gì đó tương tự như nếu bạn muốn chia nhỏ thành các nhóm khác nhau:

for j in range(0, len(second_list)): 
    for i in range(0, len(mylist), second_list[j]): 
     chunk_mylist = mylist[i:i+second_list[j]] 

Tuy nhiên, điều này không chia nhỏ như tôi muốn. Tôi muốn kết thúc với # danh sách con của tôi là len(second_list), và cũng chia một cách chính xác, và điều này mang lại nhiều hơn thế (và cũng chia tách không chính xác).

+0

gì sẽ xảy ra nếu bạn chạy ra khỏi các phần tử trong danh sách? –

Trả lời

1

Giải pháp này theo dõi số lượng mục bạn đã viết. Nó sẽ sụp đổ nếu tổng các số trong second_list dài hơn mylist

total = 0 
listChunks = [] 
for j in range(len(second_list)): 
    chunk_mylist = mylist[total:total+second_list[j]] 
    listChunks.append(chunk_mylist) 
    total += second_list[j] 

Sau khi chạy này, listChunks là một danh sách có chứa các danh sách con với độ dài được tìm thấy trong second_list.

+0

@ J.P., Bạn có thể chia sẻ nội dung 'second_list' của bạn không? Mã này hoạt động trong các trường hợp thử nghiệm của tôi. – nbryans

+1

Hãy để tôi kiểm tra lại dữ liệu của tôi (danh sách của tôi thực sự là dài) và chắc chắn - nó đã trở thành một vấn đề ở cuối của tôi, trong trường hợp này tôi nghĩ rằng nó sẽ hoạt động! Tôi sẽ kiểm tra lại và chấp nhận câu trả lời của bạn một lần. Cảm ơn! –

4

Sử dụng danh sách-comprehensions cùng với cắt và sum() chức năng (tất cả cơ bản và built-in công cụ của python):

mylist = [1,2,3,4,5,6,7,8,9,10] 
seclist = [2,4,6] 

[mylist[sum(seclist[:i]):sum(seclist[:i+1])] for i in range(len(seclist))] 

#output: 
[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10]] 

Nếu seclist là rất dài và bạn muốn có hiệu quả hơn sử dụng numpy.cumsum() trước tiên:

import numpy as np 
cumlist = np.hstack((0, np.cumsum(seclist))) 
[mylist[cumlist[i]:cumlist[i+1]] for i in range(len(cumlist)-1)] 

và nhận kết quả tương tự

+1

Đây là giải pháp ban đầu của tôi, nhưng tôi nghĩ rằng phải có một cách hiệu quả hơn so với tính toán 2 * len (seclist) khoản tiền. – jedwards

+1

@jedwards người ta có thể xây dựng [danh sách tổng tích lũy] (http://stackoverflow.com/questions/15889131/how-to-find-the-cumulative-sum-of-numbers-in-a-list) trước tiên nếu anh ta lo lắng về hiệu quả –

+0

Vâng, đó là nơi tôi đã đứng đầu - 'seps = [sum (seclist [: i]) cho tôi trong phạm vi (len (seclist) +1)]; danh sách = [mylist [i: j] cho (i, j) trong zip (seps, seps [1:])] ' – jedwards

1
subgroups = [] 
start=0 
for i in second_list: 
    subgroups.append(mylist[start:start + i]) 
    start = i + start 

Vào cuối subgroups sẽ chứa danh sách mong muốn

Ví dụ chạy:

>>> mylist = [1,2,3,4,5,6,7,8,9,10,11,12] 
>>> second_list = [2,4,5,9] 
>>> subgroups = [] 
>>> start=0 
>>> for i in second_list: 
... subgroups.append(mylist[start:start + i]) 
... start = i + start 
... 
>>> subgroups 
[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11], [12]] 
13

Bạn có thể tạo một iterator và itertools.islice:

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 
seclist = [2,4,6] 

from itertools import islice 
it = iter(mylist) 

sliced =[list(islice(it, 0, i)) for i in seclist] 

Trong đó sẽ cung cấp cho bạn:

[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12]] 

Khi các thành phần i được tiêu thụ, chúng sẽ biến mất để chúng tôi tiếp tục nhận được các yếu tố tiếp theo i.

Không chắc gì sẽ xảy ra với bất kỳ yếu tố còn lại, nếu bạn muốn họ thêm vào, bạn có thể thêm một cái gì đó như:

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ,14] 
seclist = [2, 4, 6] 

from itertools import islice 

it = iter(mylist) 

slices = [sli for sli in (list(islice(it, 0, i)) for i in seclist)] 
remaining = list(it) 
if remaining: 
    slices.append(remaining) 
print(slices) 

Trong đó sẽ cung cấp cho bạn:

[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14]] 

Hoặc ngược lại nếu có không đủ, bạn có thể sử dụng một vài phương pháp để xóa danh sách trống, một trong các biểu thức trình tạo bên trong:

from itertools import islice 

it = iter(mylist) 
slices = [sli for sli in (list(islice(it, 0, i)) for i in seclist) if sli] 

Hoặc kết hợp với itertools.takewhile:

from itertools import islice, takewhile 

it = iter(mylist) 
slices = list(takewhile(bool, (list(islice(it, 0, i)) for i in seclist))) 

nào cho:

mylist = [1, 2, 3, 4, 5, 6] 
seclist = [2, 4, 6,8] 

sẽ cung cấp cho bạn:

[[1, 2], [3, 4, 5, 6]] 

Trái ngược với:

[[1, 2], [3, 4, 5, 6], [], []] 

gì bạn sử dụng completel y phụ thuộc vào các bản in có thể của bạn và cách bạn muốn xử lý các khả năng khác nhau.

+2

Sử dụng tốt 'oflice' - tiêu thụ một lượng các mục khác nhau từ * cùng một trình lặp *. +1 – jedwards

6

Một cách tiếp cận numpythonic:

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 
>>> sec = [2, 4, 5] 
>>> np.split(lst, np.cumsum(sec)) 
[array([0, 1]), array([2, 3, 4, 5]), array([ 6, 7, 8, 9, 10]), array([11])] 

Và đây là một cách tiếp cận Python3.X sử dụng itertool.accumulate():

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 
>>> sec = [2,4,6] 
>>> from itertools import accumulate 
>>> sec = list(accumulate(sec_lst)) 
>>> sec = [0] + sec + [None] if sec[0] != 0 else sec + [None] 
>>> 
>>> [lst[i:j] for i, j in zip(sec, sec[1:])] 
[[0, 1], [2, 3, 4, 5], [6, 7, 8, 9, 10], [11]] 
Các vấn đề liên quan