Alih keluar dan ekstrak elemen pendua daripada senarai (tatasusunan) dalam Python

Perniagaan

Bahagian ini menerangkan cara menjana senarai baharu dalam Python dengan mengalih keluar atau mengekstrak elemen pendua daripada senarai (tatasusunan).

Butiran berikut diterangkan di sini.

  • Alih keluar elemen pendua dan jana penyenaraian baharu
    • Jangan simpan susunan penyenaraian asal:set()
    • Mengekalkan susunan penyenaraian asal:dict.fromkeys(),sorted()
    • Tatasusunan dua dimensi (senarai senarai)
  • Ekstrak elemen pendua dan jana senarai baharu
    • Jangan simpan susunan penyenaraian asal
    • Mengekalkan susunan penyenaraian asal
    • Tatasusunan dua dimensi (senarai senarai)

Konsep yang sama boleh digunakan pada tupel dan bukannya senarai.

Lihat artikel berikut untuk

  • Jika anda ingin menentukan sama ada senarai atau tupel mempunyai elemen pendua
  • Jika anda ingin mengekstrak elemen yang biasa atau tidak biasa di kalangan berbilang penyenaraian dan bukannya satu penyenaraian

Ambil perhatian bahawa senarai boleh menyimpan jenis data yang berbeza dan berbeza daripada tatasusunan. Jika anda ingin mengendalikan tatasusunan dalam proses yang memerlukan saiz memori dan alamat memori atau pemprosesan berangka data besar, gunakan tatasusunan (pustaka standard) atau NumPy.

Alih keluar elemen pendua dan jana penyenaraian baharu

Jangan simpan susunan penyenaraian asal:set()

Jika tidak ada keperluan untuk mengekalkan susunan senarai asal, gunakan set(), yang menjana set jenis set.

Jenis set ialah jenis data yang tidak mempunyai unsur pendua. Apabila senarai atau jenis data lain dihantar ke set(), nilai pendua diabaikan dan objek jenis set dikembalikan di mana hanya nilai unik adalah elemen.

Jika anda ingin menjadikannya tupel, gunakan tuple().

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(set(l))
# {1, 2, 3, 4, 5}

print(list(set(l)))
# [1, 2, 3, 4, 5]

Sudah tentu, ia juga boleh dibiarkan seperti yang ditetapkan. Lihat artikel berikut untuk mendapatkan maklumat lanjut tentang set jenis set.

Mengekalkan susunan penyenaraian asal:dict.fromkeys(),sorted()

Jika anda ingin mengekalkan susunan senarai asal, gunakan kaedah kelas fromkeys() jenis kamus atau fungsi terbina dalam sorted().

dict.fromkeys() mencipta objek kamus baharu yang kuncinya ialah senarai, tupel, dsb. yang dinyatakan dalam hujah. Jika hujah kedua ditinggalkan, nilainya ialah Tiada.

Oleh kerana kunci kamus tidak mempunyai unsur pendua, nilai pendua diabaikan seperti dalam set(). Di samping itu, objek kamus boleh dihantar sebagai hujah ke senarai() untuk mendapatkan senarai yang elemennya adalah kunci kamus.

print(dict.fromkeys(l))
# {3: None, 2: None, 1: None, 5: None, 4: None}

print(list(dict.fromkeys(l)))
# [3, 2, 1, 5, 4]

Ia telah dijamin sejak Python 3.7 (CPython ialah 3.6) bahawa dict.fromkeys() mengekalkan susunan urutan hujah. Versi terdahulu menggunakan fungsi terbina dalam sorted() seperti berikut.

Tentukan senarai tuple method index() untuk kekunci argumen yang diisih, yang mengembalikan senarai unsur yang diisih.

index() ialah kaedah yang mengembalikan indeks nilai (bilangan elemen dalam senarai), yang boleh ditentukan sebagai kunci sorted() untuk mengisih senarai berdasarkan susunan senarai asal. Kunci argumen ditentukan sebagai objek boleh dipanggil (boleh dipanggil), jadi jangan tulis ().

print(sorted(set(l), key=l.index))
# [3, 2, 1, 5, 4]

Tatasusunan dua dimensi (senarai senarai)

Untuk tatasusunan dua dimensi (senarai senarai), kaedah menggunakan set() atau dict.fromkeys() menghasilkan TypeError.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]

# l_2d_unique = list(set(l_2d))
# TypeError: unhashable type: 'list'

# l_2d_unique_order = dict.fromkeys(l_2d)
# TypeError: unhashable type: 'list'

Ini kerana objek tidak boleh cincang seperti senarai tidak boleh menjadi elemen set jenis atau kunci jenis dict.

Tentukan fungsi berikut Susunan senarai asal dikekalkan dan berfungsi untuk senarai dan tupel satu dimensi.

def get_unique_list(seq):
    seen = []
    return [x for x in seq if x not in seen and not seen.append(x)]

print(get_unique_list(l_2d))
# [[1, 1], [0, 1], [0, 0], [1, 0]]

print(get_unique_list(l))
# [3, 2, 1, 5, 4]

Notasi pemahaman senarai digunakan.

Di sini, kami menggunakan yang berikut

  • Jika X dalam “X dan Y” adalah palsu dalam penilaian litar pintas operator dan, maka Y tidak dinilai (tidak dilaksanakan).
  • Kaedah append() mengembalikan Tiada.

Jika unsur-unsur senarai asal seq tidak wujud dalam yang dilihat, maka dan selepas dinilai.
seen.append(x) dilaksanakan dan elemen ditambah kepada dilihat.
Kerana kaedah append() mengembalikan None dan None is False, not seen.append(x) menilai kepada True.
Ungkapan bersyarat dalam notasi pemahaman senarai menjadi Benar dan ditambah sebagai elemen senarai akhir yang dijana.

Jika unsur-unsur senarai asal seq hadir dalam dilihat, maka x tidak dilihat adalah Palsu, dan ungkapan bersyarat untuk ungkapan pemahaman senarai adalah Palsu.
Oleh itu, mereka tidak ditambah sebagai elemen senarai yang dijana akhir.

Kaedah lain ialah menetapkan paksi hujah dalam fungsi NumPy np.unique(), walaupun hasilnya akan diisih.

Ekstrak elemen pendua dan jana senarai baharu

Jangan simpan susunan penyenaraian asal

Untuk mengekstrak elemen pendua sahaja daripada senarai asal, gunakan collections.Counter().
Mengembalikan koleksi.Counter (subkelas kamus) dengan elemen sebagai kunci dan bilangan elemen sebagai nilai.

import collections

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(collections.Counter(l))
# Counter({3: 3, 2: 2, 1: 2, 5: 1, 4: 1})

Memandangkan ia adalah subkelas kamus, item() boleh digunakan untuk mendapatkan kunci dan nilai. Ia memadai untuk mengekstrak kunci yang nombornya dua atau lebih.

print([k for k, v in collections.Counter(l).items() if v > 1])
# [3, 2, 1]

Mengekalkan susunan penyenaraian asal

Seperti yang ditunjukkan dalam contoh di atas, sejak Python 3.7, kunci koleksi. Kaunter mengekalkan susunan senarai asal dan seterusnya.

Dalam versi terdahulu, pengisihan dengan sorted() sudah memadai, begitu juga dengan pemadaman elemen pendua.

print(sorted([k for k, v in collections.Counter(l).items() if v > 1], key=l.index))
# [3, 2, 1]

Jika anda ingin mengekstrak pendua sebagaimana adanya, hanya tinggalkan elemen daripada senarai asal dengan bilangan dua atau lebih. Pesanan juga dipelihara.

cc = collections.Counter(l)
print([x for x in l if cc[x] > 1])
# [3, 3, 2, 1, 1, 2, 3]

Tatasusunan dua dimensi (senarai senarai)

Untuk tatasusunan dua dimensi (senarai senarai), fungsi berikut adalah mungkin apabila susunan senarai asal tidak dikekalkan dan apabila ia dikekalkan, masing-masing. Ia juga berfungsi untuk senarai dan tupel satu dimensi.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]
def get_duplicate_list(seq):
    seen = []
    return [x for x in seq if not seen.append(x) and seen.count(x) == 2]

def get_duplicate_list_order(seq):
    seen = []
    return [x for x in seq if seq.count(x) > 1 and not seen.append(x) and seen.count(x) == 1]

print(get_duplicate_list(l_2d))
# [[0, 1], [1, 1]]

print(get_duplicate_list_order(l_2d))
# [[1, 1], [0, 1]]

print(get_duplicate_list(l))
# [3, 1, 2]

print(get_duplicate_list_order(l))
# [3, 2, 1]

Jika anda ingin mengekstrak dengan pendua, tinggalkan elemen daripada senarai asal dengan kiraan dua atau lebih.

print([x for x in l_2d if l_2d.count(x) > 1])
# [[1, 1], [0, 1], [0, 1], [1, 1], [1, 1]]

Ambil perhatian bahawa kerana kerumitan pengiraan count() ialah O(n), fungsi yang ditunjukkan di atas yang berulang kali melaksanakan count() adalah sangat tidak cekap. Mungkin ada cara yang lebih bijak.

Counter ialah subkelas kamus, jadi jika anda menghantar senarai atau tuple yang elemennya ialah senarai atau objek tidak boleh cincang lain ke collections.Counter(), ralat akan berlaku dan anda tidak akan dapat menggunakannya.

# print(collections.Counter(l_2d))
# TypeError: unhashable type: 'list'