Chuyển “danh sách các bộ giá trị” thành danh sách phẳng hoặc ma trận


82

Với Sqlite, lệnh "select..from" trả về "đầu ra" kết quả, được in ra (bằng python):

>>print output
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]

Nó dường như là một danh sách các bộ giá trị. Tôi muốn chuyển đổi "đầu ra" trong một mảng 1D đơn giản (= danh sách trong Python, tôi đoán):

[12.2817, 12.2817, 0, 0, 8.52, 8.52]

hoặc ma trận 2x3:

12.2817 12.2817
0          0 
8.52     8.52

được đọc qua "output [i] [j]"

Lệnh làm phẳng không thực hiện công việc cho tùy chọn đầu tiên và tôi không có ý tưởng cho tùy chọn thứ hai ... :)

Bạn có thể vui lòng cho tôi một gợi ý? Một số thứ nhanh sẽ tuyệt vời vì dữ liệu thực lớn hơn nhiều (đây chỉ là một ví dụ đơn giản).


2
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]đã là một ma trận 3x2 !? hay tôi đã bỏ lỡ điều gì đó?
mouad


1
cho hàm flatten itertools kiểm tra mô-đun công thức nấu ăn đã có một chức năng ví dụ flatten: docs.python.org/library/itertools.html#recipes
mouad

4
[item for sublist in output for item in sublist]hoạt động hoàn hảo và có lợi thế là các bộ giá trị bên trong của bạn cũng có thể là danh sách; nói chung hơn là bất kỳ sự kết hợp nào giữa các tác phẩm có thể lặp lại bên trong và bên ngoài
Kyss Tao

Câu trả lời:


124

Cho đến nay, giải pháp nhanh nhất (và ngắn nhất) đã được đăng:

list(sum(output, ()))

Nhanh hơn khoảng 50% so với itertoolsgiải pháp và nhanh hơn khoảng 70% so với mapgiải pháp.


8
@Joel hay quá, nhưng tôi tự hỏi nó hoạt động như thế nào? list(output[0]+output[1]+output[2])cho kết quả mong muốn nhưng list(sum(output))không. Tại sao? "Phép thuật" nào mà () làm được?
Kyss Tao

9
Ok, tôi nên đọc hướng dẫn sử dụng g . Có vẻ như sum(sequence[, start]): sum sẽ thêm startnhững giá trị mặc định 0thay vì sau đó chỉ bắt đầu từ sequence[0]nếu nó tồn tại và sau đó thêm các phần tử còn lại. Xin lỗi vì làm phiền bạn.
Kyss Tao

3
Đây là một mô hình phản đối nổi tiếng: không sử dụng sumđể nối các chuỗi, nó dẫn đến một thuật toán thời gian bậc hai. Thật vậy, sumhàm sẽ phàn nàn nếu bạn cố gắng làm điều này với chuỗi!
juanpa.arrivillaga

@ juanpa.arrivillaga: đồng ý. Có rất ít trường hợp sử dụng mà điều này sẽ thích hợp hơn.
Joel Cornett

9
Có, nhanh chóng nhưng hoàn toàn hạn chế. Bạn sẽ phải để lại nhận xét về những gì nó thực sự đang làm :(
CpILL

42

Phương pháp hiểu danh sách hoạt động với các kiểu Lặp lại và nhanh hơn các phương pháp khác được hiển thị ở đây.

flattened = [item for sublist in l for item in sublist]

llà danh sách cần làm phẳng (được gọi outputtrong trường hợp của OP)


kiểm tra thời gian:

l = list(zip(range(99), range(99)))  # list of tuples to flatten

Danh sách hiểu

[item for sublist in l for item in sublist]

kết quả thời gian = 7,67 µs ± 129 ns mỗi vòng

Danh sách phương thức expand ()

flattened = []
list(flattened.extend(item) for item in l)

kết quả thời gian = 11 µs ± 433 ns mỗi vòng lặp

Tổng()

list(sum(l, ()))

kết quả thời gian = 24,2 µs ± 269 ns mỗi vòng lặp


1
Tôi đã phải sử dụng điều này trên một tập dữ liệu lớn, phương pháp hiểu danh sách cho đến nay là nhanh nhất!
nbeuchat

Tôi đã thực hiện một chút thay đổi đối với giải pháp .extend và bây giờ hoạt động tốt hơn một chút. kiểm tra nó vào thời gian của bạn để so sánh
Totoro

24

Trong Python 2.7 và tất cả các phiên bản của Python3, bạn có thể sử dụng itertools.chainđể làm phẳng danh sách các tệp lặp. Với *cú pháp hoặc phương thức lớp.

>>> t = [ (1,2), (3,4), (5,6) ]
>>> t
[(1, 2), (3, 4), (5, 6)]
>>> import itertools
>>> list(itertools.chain(*t))
[1, 2, 3, 4, 5, 6]
>>> list(itertools.chain.from_iterable(t))
[1, 2, 3, 4, 5, 6]

11

Cập nhật : Làm phẳng bằng cách sử dụng mở rộng nhưng không hiểu và không sử dụng danh sách làm trình lặp (nhanh nhất)

Sau khi kiểm tra câu trả lời tiếp theo cho câu trả lời này cung cấp giải pháp nhanh hơn thông qua khả năng hiểu danh sách với dual fortôi đã thực hiện một chút chỉnh sửa và bây giờ nó hoạt động tốt hơn, đầu tiên việc thực thi danh sách (...) đã kéo một phần trăm thời gian lớn, sau đó thay đổi danh sách khả năng hiểu cho một vòng lặp đơn giản cũng được cạo thêm một chút.

Giải pháp mới là:

l = []
for row in output: l.extend(row)

Lớn hơn:

Làm phẳng với bản đồ / mở rộng:

l = []
list(map(l.extend, output))

Làm phẳng bằng khả năng hiểu danh sách thay vì bản đồ

l = []
list(l.extend(row) for row in output)

một số thời gian cho phần mở rộng mới và cải tiến nhận được bằng cách xóa danh sách (...) cho [...]:

import timeit
t = timeit.timeit
o = "output=list(zip(range(1000000000), range(10000000))); l=[]"
steps_ext = "for row in output: l.extend(row)"
steps_ext_old = "list(l.extend(row) for row in output)"
steps_ext_remove_list = "[l.extend(row) for row in output]"
steps_com = "[item for sublist in output for item in sublist]"

print("new extend:      ", t(steps_ext, setup=o, number=10))
print("old extend w []: ", t(steps_ext_remove_list, setup=o, number=10))
print("comprehension:   ", t(steps_com, setup=o, number=10,))
print("old extend:      ", t(steps_ext_old, setup=o, number=10))

>>> new extend:       4.502427191007882
>>> old extend w []:  5.281140706967562
>>> comprehension:    5.54302118299529
>>> old extend:       6.840151469223201    

9

itertoolschuỗi sử dụng :

>>> import itertools
>>> list(itertools.chain.from_iterable([(12.2817, 12.2817), (0, 0), (8.52, 8.52)]))
[12.2817, 12.2817, 0, 0, 8.52, 8.52]

7
>>> flat_list = []
>>> nested_list = [(1, 2, 4), (0, 9)]
>>> for a_tuple in nested_list:
...     flat_list.extend(list(a_tuple))
... 
>>> flat_list
[1, 2, 4, 0, 9]
>>> 

bạn có thể dễ dàng di chuyển từ danh sách bộ sang danh sách đơn như được hiển thị ở trên.


7

Hoặc bạn có thể làm phẳng danh sách như sau:

reduce(lambda x,y:x+y, map(list, output))

reduce(lambda x,y:x+y, output)dường như hoạt động trực tiếp chuyển đổi thành một bộ dài (có thể được chuyển đổi thành một danh sách). Tại sao sử dụng map(list, output)bên trong reduce()cuộc gọi? Có lẽ Nó phù hợp hơn với thực tế là các bộ giá trị là bất biến, các danh sách có thể thay đổi .
Paul Rougieux

5

Đây là những gì numpyđược tạo ra, cả từ cấu trúc dữ liệu, cũng như quan điểm tốc độ.

import numpy as np

output = [(12.2817, 12.2817), (0, 0), (8.52, 8.52)]
output_ary = np.array(output)   # this is your matrix 
output_vec = output_ary.ravel() # this is your 1d-array

2

Trong trường hợp danh sách lồng nhau tùy ý (chỉ trong trường hợp):

def flatten(lst):
    result = []
    for element in lst: 
        if hasattr(element, '__iter__'):
            result.extend(flatten(element))
        else:
            result.append(element)
    return result

>>> flatten(output)
[12.2817, 12.2817, 0, 0, 8.52, 8.52]
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.