Saya memiliki daftar A:

A = [['512', '102']
['410', '105']
['820', '520']]

Dan daftar B:

B = [['510', '490', '512', '912']
['512', '108', '102', '520' , '901', '821']
['510', '118', '284']]

Saya hanya ingin membiarkan baris-baris ini dalam daftar A, yang semua nilainya terkandung dalam setidaknya satu baris dari daftar B. Jadi output yang saya harapkan adalah:

[['512', '102']]

Karena nilai '512' dan '102' berada di baris kedua daftar B.

Saya tahu cara mencapainya dengan mengulangi atau setiap item dalam daftar A dan membandingkan dengan setiap elemen dalam daftar B tetapi masalahnya adalah saya memiliki ~500000 baris dalam daftar A dan ~10000 baris dalam daftar B dan ini sangat lambat.

Apakah ada cara untuk mencapainya dengan cara yang lebih optimal?

0
aozk 14 Januari 2021, 09:58

3 jawaban

Jawaban Terbaik

Anda pasti harus bekerja dengan set di sini, karena mereka jauh lebih cepat daripada daftar.

Inilah salah satu solusinya:

[i for i in A if any(set(i)-set(k)==set() for k in B)]

Hasil

[['512', '102']]

Penjelasan:

set(i)-set(k)==set()

Memeriksa apakah semua item i termasuk dalam k

any(set(i)-set(k)==set() for k in B)

Memeriksa apakah hal di atas berlaku untuk item B apa pun untuk item A tertentu dan akhirnya

[i for i in A if any(set(i)-set(k)==set() for k in B)]

Mengembalikan semua item A yang memenuhi kondisi di atas

1
IoaTzimas 14 Januari 2021, 07:15

Anda dapat membuat daftar B sebagai kumpulan semua item secara unik dan kemudian memeriksa apakah setiap daftar dalam daftar A memiliki semua item dalam set_B

set_B= {item for sublist in B for item in sublist}
print([i for i in A if len(set(i).difference(set_B)) == 0])

Keluaran

[['512', '102']]
1
Leo Arad 14 Januari 2021, 07:16

Saya penasaran jadi saya menjalankan kode untuk menguji, dan berakhir dengan hasil yang mengejutkan. Pilihan lain adalah menggunakan kode ini (jika Anda hanya memiliki 2 angka di setiap baris A):

for num1, num2 in A:
  for b1 in B:
    if num1 in b1:
      for b2 in B:
        if num2 in b2:
          result.append([num1, num2])
          break
      break

Saya menguji ini dengan cara pemahaman set + daftar dalam jawaban oleh @IoaTzimas seperti:

import timeit

a = '''for num1, num2 in A:
  for b in B:
    if num1 in b and num2 in b:
      result.append([num1, num2])
      break'''

b = '[i for i in A if any(set(i)-set(k)==set() for k in B)]'


print(min(timeit.Timer(a, setup = '''A = [['512', '102'],
['410', '105'],
['820', '520']]

B = [['510', '490', '512', '912'],
['512', '108', '102', '520' , '901', '821'],
['510', '118', '284']]
result = []''').repeat(100,10000)))


print(min(timeit.Timer(b, setup = '''A = [['512', '102'],
['410', '105'],
['820', '520']]

B = [['510', '490', '512', '912'],
['512', '108', '102', '520' , '901', '821'],
['510', '118', '284']]''').repeat(100,10000)))

Dan hasil yang tercetak adalah:

0.010839237002073787
0.05843622000247706

Ini menunjukkan bahwa metode set bisa menjadi sedikit lebih lambat (waktunya dalam detik) daripada metode for loop. Jarak tempuh Anda mungkin berbeda: itu tergantung pada kumpulan data dan waktu hari tidak diragukan lagi. Tetapi patut dicoba jika metode yang ditetapkan terlalu lama.

1
anvoice 14 Januari 2021, 08:04