Chia danh sách thành các danh sách nhỏ hơn (chia làm đôi)


150

Tôi đang tìm cách để dễ dàng chia một danh sách trăn làm đôi.

Vì vậy, nếu tôi có một mảng:

A = [0,1,2,3,4,5]

Tôi sẽ có thể nhận được:

B = [0,1,2]

C = [3,4,5]

Câu trả lời:


226
A = [1,2,3,4,5,6]
B = A[:len(A)//2]
C = A[len(A)//2:]

Nếu bạn muốn một chức năng:

def split_list(a_list):
    half = len(a_list)//2
    return a_list[:half], a_list[half:]

A = [1,2,3,4,5,6]
B, C = split_list(A)

70
Bạn cần buộc chia int trong Python 3. // là bắt buộc.
Stefan Kendall

4
Giải pháp tốt đẹp, cảm ơn. Nó cũng hoạt động với các phân số như 80/20 trong Python3B = A[:(len(A) // 10) * 8] C = A[(len(A) // 10) * 8:]
Gergely M

87

Một giải pháp chung chung hơn một chút (bạn có thể chỉ định số lượng phần bạn muốn, không chỉ chia 'một nửa'):

EDIT : bài đăng được cập nhật để xử lý độ dài danh sách lẻ

EDIT2 : cập nhật bài viết một lần nữa dựa trên ý kiến ​​thông tin Brians

def split_list(alist, wanted_parts=1):
    length = len(alist)
    return [ alist[i*length // wanted_parts: (i+1)*length // wanted_parts] 
             for i in range(wanted_parts) ]

A = [0,1,2,3,4,5,6,7,8,9]

print split_list(A, wanted_parts=1)
print split_list(A, wanted_parts=2)
print split_list(A, wanted_parts=8)

2
Khi danh sách không chia đều (ví dụ: split_list ([1,2,3], 2)), điều này thực sự sẽ trả về danh sách Want_parts + 1.
Brian

3
Một cách tốt hơn tôi nghĩ sẽ là: length = len (alist); return [alist [i * length // Want_parts: (i + 1) * length // Want_parts] cho i trong phạm vi (Want_parts)]. Bằng cách đó, bạn có được một bản phân phối đồng đều nhất có thể và luôn nhận được chính xác các mục Want_parts (ngay cả các miếng đệm với [] if Want_parts> len (A))
Brian

2
hi .. ký hiệu "//" nghĩa là gì ??
frazman

2
@Fraz Nó có nghĩa là bình luận nội tuyến. Bỏ qua "// Want_parts" và "// Want_parts" để thực thi tập lệnh.
PunjCoder

19
//nghĩa là chia số nguyên. Họ không nên bị bỏ rơi vì họ khá cần thiết trong việc thực hiện công việc này.
Alphadelta14

43
f = lambda A, n=3: [A[i:i+n] for i in range(0, len(A), n)]
f(A)

n - độ dài được xác định trước của mảng kết quả


1
Điều này hoạt động rất tốt trong tình huống của tôi, tuy nhiên nó đang nối thêm mọi chỉ mục cuối cùng khác của mỗi danh sách vào danh sách riêng của nó. Khó để giải thích. Vui lòng trả lời nếu bạn có thể giúp đỡ và tôi sẽ giải thích thêm.
Mike Issa

34
def split(arr, size):
     arrs = []
     while len(arr) > size:
         pice = arr[:size]
         arrs.append(pice)
         arr   = arr[size:]
     arrs.append(arr)
     return arrs

Kiểm tra:

x=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
print(split(x, 5))

kết quả:

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

1
cũng hữu ích để chuyển đổi danh sách thành ma trận
mpgn

Điều này hoạt động, nhưng không hoàn toàn. Tôi đang sử dụng chức năng này trong một vòng lặp, và độ dài khác nhau. Nói cách khác : for i,j in zip(list,lengths): print(split(i,j)). Các danh sách listlengthscó cùng độ dài. j là xen kẽ: 5,4,5,4,5 và hàm phân chia hoạt động trên hai lần thay thế đầu tiên, tức là nó chia tách idanh sách đầu tiên cho 5 và 4, NHƯNG trong lần lặp tiếp theo, nó sẽ chia nó ở 4,4, 1. : \ Vui lòng trả lời nếu bạn muốn tôi giải thích thêm (đăng câu hỏi mới)
Mike Issa

15

Nếu bạn không quan tâm đến thứ tự ...

def split(list):  
    return list[::2], list[1::2]

list[::2]được mọi phần tử thứ hai trong danh sách bắt đầu từ phần tử thứ 0.
list[1::2]được mọi phần tử thứ hai trong danh sách bắt đầu từ phần tử thứ nhất.


4
Đặt tên cẩn thận cho arg listvới bóng đổ tích list(...)hợp. Tôi đã nhìn thấy lstlist_sử dụng phổ biến để tránh nó.
Taylor Edmiston

3
điều này cảm thấy nhất là pythonic (bỏ qua việc đặt tên không chính xác)
Tjorriemorrie


11

Đây là một giải pháp phổ biến, chia mảng thành phần đếm

def split(arr, count):
     return [arr[i::count] for i in range(count)]

Điều này làm mất thứ tự của danh sách
Timmah

9
def splitter(A):
    B = A[0:len(A)//2]
    C = A[len(A)//2:]

 return (B,C)

Tôi đã thử nghiệm và dấu gạch chéo kép được yêu cầu để buộc phân chia int trong python 3. Bài viết gốc của tôi là chính xác, mặc dù wysiwyg đã phá vỡ trong Opera, vì một số lý do.


nó không xử lý len lẻ (A) - bạn có giải pháp nào cho việc đó không?
N997

6

Có một biên nhận Python chính thức cho trường hợp tổng quát hơn là chia một mảng thành các mảng có kích thước nhỏ hơn n.

from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Đoạn mã này là từ trang tài liệu itertools python .


6

Sử dụng danh sách cắt . Cú pháp cơ bản làmy_list[start_index:end_index]

>>> i = [0,1,2,3,4,5]
>>> i[:3] # same as i[0:3] - grabs from first to third index (0->2)
[0, 1, 2]
>>> i[3:] # same as i[3:len(i)] - grabs from fourth index to end
[3, 4, 5]

Để có được nửa đầu của danh sách, bạn cắt từ chỉ mục đầu tiên sang len(i)//2( //phân chia số nguyên - vì vậy 3//2 will give the floored result of1 , instead of the invalid list index of1,5`):

>>> i[:len(i)//2]
[0, 1, 2]

..và hoán đổi các giá trị xung quanh để có được nửa thứ hai:

>>> i[len(i)//2:]
[3, 4, 5]

những gì về danh sách len lẻ)
N997

@ N997 Mã vẫn hoạt động; bạn chỉ cần kết thúc với số lượng mục khác nhau trong mỗi danh sách. Vì vậy, giả sử danh sách dài ba mục, toán tử phân chia kết quả 3//2sẽ đưa ra 1, sau đó bạn nhận được phần i[:1]nào cung cấp cho bạn [0]và phần i[1:]nào mang lại[1, 2]
dbr

3

Nếu bạn có một danh sách lớn, tốt hơn là sử dụng itertools và viết một hàm để mang lại từng phần khi cần:

from itertools import islice

def make_chunks(data, SIZE):
    it = iter(data)
    # use `xragne` if you are in python 2.7:
    for i in range(0, len(data), SIZE):
        yield [k for k in islice(it, SIZE)]

Bạn có thể sử dụng như thế này:

A = [0, 1, 2, 3, 4, 5, 6]

size = len(A) // 2

for sample in make_chunks(A, size):
    print(sample)

Đầu ra là:

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

Cảm ơn @thefourtheye @Bede Constantinides


3

10 năm sau .. tôi nghĩ - tại sao không thêm cái khác:

arr = 'Some random string' * 10; n = 4
print([arr[e:e+n] for e in range(0,len(arr),n)])

2

Mặc dù các câu trả lời ở trên ít nhiều đúng, bạn có thể gặp rắc rối nếu kích thước của mảng không chia hết cho 2, do đó a / 2, là một số lẻ, là một số float trong python 3.0 và trong phiên bản trước đó nếu bạn chỉ định from __future__ import divisionở đầu tập lệnh của bạn. Trong mọi trường hợp, tốt hơn hết là bạn nên phân chia số nguyên, nghĩa là a // 2, để có được khả năng tương thích "chuyển tiếp" của mã của bạn.


2

Điều này tương tự như các giải pháp khác, nhưng nhanh hơn một chút.

# Usage: split_half([1,2,3,4,5]) Result: ([1, 2], [3, 4, 5])

def split_half(a):
    half = len(a) >> 1
    return a[:half], a[half:]

Khéo léo sử dụng dịch chuyển nhị phân!
Janusz Skonieczny

0

Với gợi ý từ @ChristopheD

def line_split(N, K=1):
    length = len(N)
    return [N[i*length/K:(i+1)*length/K] for i in range(K)]

A = [0,1,2,3,4,5,6,7,8,9]
print line_split(A,1)
print line_split(A,2)

0
#for python 3
    A = [0,1,2,3,4,5]
    l = len(A)/2
    B = A[:int(l)]
    C = A[int(l):]       

0

Một vấn đề khác về vấn đề này vào năm 2020 ... Đây là một khái quát của vấn đề. Tôi diễn giải 'chia một danh sách thành một nửa' thành .. (nghĩa là chỉ có hai danh sách và sẽ không có sự lan tỏa đến mảng thứ ba trong trường hợp có một số lẻ, v.v.). Chẳng hạn, nếu độ dài mảng là 19 và chia cho hai bằng cách sử dụng toán tử // cho 9 và cuối cùng chúng ta sẽ có hai mảng có độ dài 9 và một mảng (thứ ba) có độ dài 1 (trong tổng số ba mảng). Nếu chúng ta muốn một giải pháp chung để cung cấp hai mảng mọi lúc, tôi sẽ cho rằng chúng ta hài lòng với các mảng bộ đôi kết quả không dài bằng nhau (một mảng sẽ dài hơn các mảng khác). Và rằng nó được coi là ok để có thứ tự hỗn hợp (xen kẽ trong trường hợp này).

"""
arrayinput --> is an array of length N that you wish to split 2 times
"""
ctr = 1 # lets initialize a counter

holder_1 = []
holder_2 = []

for i in range(len(arrayinput)): 

    if ctr == 1 :
        holder_1.append(arrayinput[i])
    elif ctr == 2: 
        holder_2.append(arrayinput[i])

    ctr += 1 

    if ctr > 2 : # if it exceeds 2 then we reset 
        ctr = 1 

Khái niệm này hoạt động cho bất kỳ số lượng phân vùng danh sách nào bạn muốn (bạn phải điều chỉnh mã tùy thuộc vào số lượng phần danh sách bạn muốn). Và là khá đơn giản để giải thích. Để tăng tốc mọi thứ, bạn thậm chí có thể viết vòng lặp này bằng cython / C / C ++ để tăng tốc mọi thứ. Sau đó, một lần nữa, tôi đã thử mã này trên các danh sách tương đối nhỏ ~ 10.000 hàng và nó kết thúc sau một phần giây.

Chỉ hai xu của tôi.

Cảm ơn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.