5. Struktur Data
****************

Bab ini menjelaskan beberapa hal yang telah Anda pelajari secara lebih
rinci, dan menambahkan beberapa hal baru juga.


5.1. Lebih Lanjut tentang Daftar *Lists*
========================================

Tipe data daftar *list* memiliki beberapa metode lagi. Berikut ini
semua metode dari objek daftar *list*:

list.append(x)

   Add an item to the end of the list; equivalent to "a[len(a):] =
   [x]".

list.extend(L)

   Extend the list by appending all the items in the given list;
   equivalent to "a[len(a):] = L".

list.insert(i, x)

   Masukkan item pada posisi tertentu. Argumen pertama adalah indeks
   elemen sebelum memasukkan, jadi "a.insert(0, x)" memasukkan di
   bagian depan daftar *list*, dan "a.insert(len(a), x)" sama dengan
   "a.append(x)".

list.remove(x)

   Remove the first item from the list whose value is *x*. It is an
   error if there is no such item.

list.pop([i])

   Hapus item pada posisi yang diberikan dalam daftar, dan kembalikan.
   Jika tidak ada indeks yang ditentukan, "a.pop()" menghapus dan
   mengembalikan item terakhir dalam daftar. (Tanda kurung siku di
   sekitar *i* dalam pengenal *signature* metode menunjukkan bahwa
   parameternya opsional, bukan Anda harus mengetik tanda kurung siku
   pada posisi itu. Anda akan sering melihat notasi ini di Referensi
   Pustaka Python.)

list.index(x)

   Return the index in the list of the first item whose value is *x*.
   It is an error if there is no such item.

list.count(x)

   Kembalikan berapa kali *x* muncul dalam daftar.

list.sort(cmp=None, key=None, reverse=False)

   Urutkan item daftar di tempat (argumen dapat digunakan untuk
   mengurutkan ubahsuaian *customization*, lihat "sorted()" untuk
   penjelasannya).

list.reverse()

   Reverse the elements of the list, in place.

Contoh yang menggunakan sebagian besar metode daftar *list*:

   >>> a = [66.25, 333, 333, 1, 1234.5]
   >>> print a.count(333), a.count(66.25), a.count('x')
   2 1 0
   >>> a.insert(2, -1)
   >>> a.append(333)
   >>> a
   [66.25, 333, -1, 333, 1, 1234.5, 333]
   >>> a.index(333)
   1
   >>> a.remove(333)
   >>> a
   [66.25, -1, 333, 1, 1234.5, 333]
   >>> a.reverse()
   >>> a
   [333, 1234.5, 1, 333, -1, 66.25]
   >>> a.sort()
   >>> a
   [-1, 1, 66.25, 333, 333, 1234.5]
   >>> a.pop()
   1234.5
   >>> a
   [-1, 1, 66.25, 333, 333]

You might have noticed that methods like "insert", "remove" or "sort"
that only modify the list have no return value printed -- they return
the default "None".  This is a design principle for all mutable data
structures in Python.


5.1.1. Menggunakan Daftar *Lists* sebagai Tumpukan *Stacks*
-----------------------------------------------------------

Metode daftar membuatnya sangat mudah untuk menggunakan daftar *lust*
sebagai tumpukan *stack*, di mana elemen terakhir yang ditambahkan
adalah elemen pertama yang diambil ("last-in, first-out"). Untuk
menambahkan item ke atas tumpukan, gunakan "append()". Untuk mengambil
item dari atas tumpukan, gunakan "pop()" tanpa indeks eksplisit.
Sebagai contoh:

   >>> stack = [3, 4, 5]
   >>> stack.append(6)
   >>> stack.append(7)
   >>> stack
   [3, 4, 5, 6, 7]
   >>> stack.pop()
   7
   >>> stack
   [3, 4, 5, 6]
   >>> stack.pop()
   6
   >>> stack.pop()
   5
   >>> stack
   [3, 4]


5.1.2. Menggunakan Daftar *Lists* sebagai Antrian *Queues*
----------------------------------------------------------

Dimungkinkan juga untuk menggunakan daftar sebagai antrian, di mana
elemen pertama yang ditambahkan adalah elemen pertama yang diambil
("first-in, first-out"); namun, daftar tidak efisien untuk tujuan ini.
Sementara menambahkan dan muncul dari akhir daftar cepat, melakukan
memasukkan atau muncul dari awal daftar lambat (karena semua elemen
lain harus digeser satu).

Untuk mengimplementasikan antrian, gunakan "collections.deque" yang
dirancang untuk menambahkan dan muncul dengan cepat dari kedua
ujungnya. Sebagai contoh:

   >>> from collections import deque
   >>> queue = deque(["Eric", "John", "Michael"])
   >>> queue.append("Terry")           # Terry arrives
   >>> queue.append("Graham")          # Graham arrives
   >>> queue.popleft()                 # The first to arrive now leaves
   'Eric'
   >>> queue.popleft()                 # The second to arrive now leaves
   'John'
   >>> queue                           # Remaining queue in order of arrival
   deque(['Michael', 'Terry', 'Graham'])


5.1.3. Functional Programming Tools
-----------------------------------

There are three built-in functions that are very useful when used with
lists: "filter()", "map()", and "reduce()".

"filter(function, sequence)" returns a sequence consisting of those
items from the sequence for which "function(item)" is true. If
*sequence* is a "str", "unicode" or "tuple", the result will be of the
same type; otherwise, it is always a "list".  For example, to compute
a sequence of numbers divisible by 3 or 5:

   >>> def f(x): return x % 3 == 0 or x % 5 == 0
   ...
   >>> filter(f, range(2, 25))
   [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]

"map(function, sequence)" calls "function(item)" for each of the
sequence's items and returns a list of the return values.  For
example, to compute some cubes:

   >>> def cube(x): return x*x*x
   ...
   >>> map(cube, range(1, 11))
   [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

More than one sequence may be passed; the function must then have as
many arguments as there are sequences and is called with the
corresponding item from each sequence (or "None" if some sequence is
shorter than another).  For example:

   >>> seq = range(8)
   >>> def add(x, y): return x+y
   ...
   >>> map(add, seq, seq)
   [0, 2, 4, 6, 8, 10, 12, 14]

"reduce(function, sequence)" returns a single value constructed by
calling the binary function *function* on the first two items of the
sequence, then on the result and the next item, and so on.  For
example, to compute the sum of the numbers 1 through 10:

   >>> def add(x,y): return x+y
   ...
   >>> reduce(add, range(1, 11))
   55

If there's only one item in the sequence, its value is returned; if
the sequence is empty, an exception is raised.

A third argument can be passed to indicate the starting value.  In
this case the starting value is returned for an empty sequence, and
the function is first applied to the starting value and the first
sequence item, then to the result and the next item, and so on.  For
example,

   >>> def sum(seq):
   ...     def add(x,y): return x+y
   ...     return reduce(add, seq, 0)
   ...
   >>> sum(range(1, 11))
   55
   >>> sum([])
   0

Don't use this example's definition of "sum()": since summing numbers
is such a common need, a built-in function "sum(sequence)" is already
provided, and works exactly like this.


5.1.4. Daftar *List* *Comprehensions*
-------------------------------------

Pemahaman daftar *list comprehensions* menyediakan cara singkat untuk
membuat daftar. Aplikasi umum adalah membuat daftar baru di mana
setiap elemen adalah hasil dari beberapa operasi yang diterapkan pada
setiap anggota dari urutan lain atau *iterable*, atau untuk membuat
urutan elemen-elemen yang memenuhi kondisi tertentu.

Misalnya, anggap kita ingin membuat daftar kotak, seperti:

   >>> squares = []
   >>> for x in range(10):
   ...     squares.append(x**2)
   ...
   >>> squares
   [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

We can obtain the same result with:

   squares = [x**2 for x in range(10)]

This is also equivalent to "squares = map(lambda x: x**2, range(10))",
but it's more concise and readable.

A list comprehension consists of brackets containing an expression
followed by a "for" clause, then zero or more "for" or "if" clauses.
The result will be a new list resulting from evaluating the expression
in the context of the "for" and "if" clauses which follow it. For
example, this listcomp combines the elements of two lists if they are
not equal:

   >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

and it's equivalent to:

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Perhatikan bagaimana urutan pernyataan "for" dan "if" adalah sama di
kedua cuplikan ini.

Jika ekspresi adalah tuple (mis. "(x, y)" dalam contoh sebelumnya),
ekspresi tersebut harus diberi kurung.

   >>> vec = [-4, -2, 0, 2, 4]
   >>> # create a new list with the values doubled
   >>> [x*2 for x in vec]
   [-8, -4, 0, 4, 8]
   >>> # filter the list to exclude negative numbers
   >>> [x for x in vec if x >= 0]
   [0, 2, 4]
   >>> # apply a function to all the elements
   >>> [abs(x) for x in vec]
   [4, 2, 0, 2, 4]
   >>> # call a method on each element
   >>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
   >>> [weapon.strip() for weapon in freshfruit]
   ['banana', 'loganberry', 'passion fruit']
   >>> # create a list of 2-tuples like (number, square)
   >>> [(x, x**2) for x in range(6)]
   [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
   >>> # the tuple must be parenthesized, otherwise an error is raised
   >>> [x, x**2 for x in range(6)]
     File "<stdin>", line 1, in <module>
       [x, x**2 for x in range(6)]
                  ^
   SyntaxError: invalid syntax
   >>> # flatten a list using a listcomp with two 'for'
   >>> vec = [[1,2,3], [4,5,6], [7,8,9]]
   >>> [num for elem in vec for num in elem]
   [1, 2, 3, 4, 5, 6, 7, 8, 9]

Pemahaman daftar *list comprehensions* dapat berisi ekspresi kompleks
dan fungsi bersarang:

   >>> from math import pi
   >>> [str(round(pi, i)) for i in range(1, 6)]
   ['3.1', '3.14', '3.142', '3.1416', '3.14159']


5.1.4.1. Pemahaman Daftar *List Comprehensions* Bersarang
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ekspresi awal dalam pemahaman daftar *list comprehension* dapat berupa
ekspresi acak *arbitrary*, termasuk pemahaman daftar *list
comprehension* lainnya.

Perhatikan contoh matriks 3x4 berikut yang diimplementasikan sebagai
daftar *list* 3 dari daftar *list* panjang 4

   >>> matrix = [
   ...     [1, 2, 3, 4],
   ...     [5, 6, 7, 8],
   ...     [9, 10, 11, 12],
   ... ]

Pemahaman daftar *list comprehension* berikut akan mengubah baris dan
kolom:

   >>> [[row[i] for row in matrix] for i in range(4)]
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Seperti yang kita lihat di bagian sebelumnya, *listcomp* bersarang
dievaluasi dalam konteks "for" yang mengikutinya, jadi contoh ini
setara dengan:

   >>> transposed = []
   >>> for i in range(4):
   ...     transposed.append([row[i] for row in matrix])
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

yang, pada gilirannya, sama dengan:

   >>> transposed = []
   >>> for i in range(4):
   ...     # the following 3 lines implement the nested listcomp
   ...     transposed_row = []
   ...     for row in matrix:
   ...         transposed_row.append(row[i])
   ...     transposed.append(transposed_row)
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Di dunia nyata, Anda harus memilih fungsi bawaan untuk pernyataan
aliran *flow* yang kompleks. Fungsi "zip()" akan melakukan pekerjaan
yang baik untuk kasus penggunaan ini:

   >>> zip(*matrix)
   [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

Lihat *tut-unpacking-argumen* untuk detail tentang tanda bintang
*asterisk* di baris ini.


5.2. The "del" statement
========================

There is a way to remove an item from a list given its index instead
of its value: the "del" statement.  This differs from the "pop()"
method which returns a value.  The "del" statement can also be used to
remove slices from a list or clear the entire list (which we did
earlier by assignment of an empty list to the slice).  For example:

   >>> a = [-1, 1, 66.25, 333, 333, 1234.5]
   >>> del a[0]
   >>> a
   [1, 66.25, 333, 333, 1234.5]
   >>> del a[2:4]
   >>> a
   [1, 66.25, 1234.5]
   >>> del a[:]
   >>> a
   []

"del" juga dapat digunakan untuk menghapus seluruh variabel:

   >>> del a

Merujuk nama "a" selanjutnya adalah kesalahan (setidaknya sampai nilai
lain ditetapkan untuknya). Kita akan menemukan kegunaan lain untuk
"del" nanti.


5.3. Tuples and *Urutan* Sequences
==================================

Kita melihat bahwa daftar *list* dan string memiliki banyak properti
yang sama, seperti operasi pengindeksan dan pemotongan. Mereka adalah
dua contoh tipe data *sequence* (lihat Sequence Types --- str,
unicode, list, tuple, bytearray, buffer, xrange). Karena Python adalah
bahasa yang berkembang, tipe data urutan lainnya dapat ditambahkan.
Ada juga tipe data urutan standar lain: *tuple*.

Sebuah *tuple* terdiri dari sejumlah nilai yang dipisahkan oleh koma,
misalnya:

   >>> t = 12345, 54321, 'hello!'
   >>> t[0]
   12345
   >>> t
   (12345, 54321, 'hello!')
   >>> # Tuples may be nested:
   ... u = t, (1, 2, 3, 4, 5)
   >>> u
   ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
   >>> # Tuples are immutable:
   ... t[0] = 88888
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'tuple' object does not support item assignment
   >>> # but they can contain mutable objects:
   ... v = ([1, 2, 3], [3, 2, 1])
   >>> v
   ([1, 2, 3], [3, 2, 1])

Seperti yang Anda lihat, pada *tuple* keluaran selalu tertutup dalam
tanda kurung, sehingga *tuple* bersarang *nester* ditafsirkan dengan
benar; mereka mungkin dimasukkan dengan atau tanpa tanda kurung di
sekitarnya, meskipun seringkali tanda kurung diperlukan pula (jika
tuple adalah bagian dari ekspresi yang lebih besar). Tidak mungkin
untuk memberikan nilai ke masing-masing item *tuple*, namun
dimungkinkan untuk membuat tuple yang berisi objek yang bisa berubah
*mutable*, seperti daftar.

Meskipun *tuple* mungkin mirip dengan daftar, *tuple* sering digunakan
dalam situasi yang berbeda dan untuk tujuan yang berbeda. *Tuples*
adalah *immutable*, dan biasanya berisi urutan elemen yang heterogen
yang diakses melalui *unpacking* (lihat nanti di bagian ini) atau
pengindeksan (atau bahkan berdasarkan atribut dalam kasus "namedtuples
<collections.namedtuple> `). Daftar adalah :term:`mutable()", dan
elemen-elemennya biasanya homogen dan diakses dengan menyusuri
*iterating* daftar *list*.

Masalah khusus adalah pembangunan *tuple* yang mengandung 0 atau 1
item: sintaksis memiliki beberapa kebiasaan *quirks* tambahan untuk
mengakomodasi ini. *Tuple* kosong dibangun oleh sepasang kurung
kosong; tupel dengan satu item dikonstruksi dengan mengikuti nilai
dengan koma (tidak cukup untuk menyertakan nilai tunggal dalam tanda
kurung). Jelek, tapi efektif. Sebagai contoh:

   >>> empty = ()
   >>> singleton = 'hello',    # <-- note trailing comma
   >>> len(empty)
   0
   >>> len(singleton)
   1
   >>> singleton
   ('hello',)

Pernyataan "t = 12345, 54321, 'hello!'" Adalah contoh dari *tuple
packing*: nilainya "12345", "54321" dan "'hello!'" Dikemas bersama-
sama dalam *tuple*. Operasi terbalik juga dimungkinkan

   >>> x, y, z = t

This is called, appropriately enough, *sequence unpacking* and works
for any sequence on the right-hand side.  Sequence unpacking requires
the list of variables on the left to have the same number of elements
as the length of the sequence.  Note that multiple assignment is
really just a combination of tuple packing and sequence unpacking.


5.4. Himpunan *Set*
===================

Python juga menyertakan tipe data untuk *sets*. Himpunan atau *Set*
adalah koleksi yang tidak terurut tanpa elemen duplikat. Penggunaan
dasar termasuk pengujian keanggotaan dan menghilangkan entri duplikat.
Atur objek juga mendukung operasi matematika seperti penyatuan
*union*, persimpangan *intersection*, perbedaan *difference*, dan
perbedaan simetris.

Kurung kurawal atau fungsi "set()" dapat digunakan untuk membuat
himpunan. Catatan: untuk membuat himpunan kosong Anda harus
menggunakan "set()", bukan "{}"; yang terakhir itu membuat kamus
*dictionary* kosong, struktur data yang kita bahas di bagian
selanjutnya.

Berikut ini adalah demonstrasi singkat:

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> fruit = set(basket)               # create a set without duplicates
   >>> fruit
   set(['orange', 'pear', 'apple', 'banana'])
   >>> 'orange' in fruit                 # fast membership testing
   True
   >>> 'crabgrass' in fruit
   False

   >>> # Demonstrate set operations on unique letters from two words
   ...
   >>> a = set('abracadabra')
   >>> b = set('alacazam')
   >>> a                                  # unique letters in a
   set(['a', 'r', 'b', 'c', 'd'])
   >>> a - b                              # letters in a but not in b
   set(['r', 'd', 'b'])
   >>> a | b                              # letters in either a or b
   set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
   >>> a & b                              # letters in both a and b
   set(['a', 'c'])
   >>> a ^ b                              # letters in a or b but not both
   set(['r', 'd', 'b', 'm', 'z', 'l'])

Seperti halnya untuk list comprehensions, *set comprehensions* juga
didukung:

   >>> a = {x for x in 'abracadabra' if x not in 'abc'}
   >>> a
   set(['r', 'd'])


5.5. Kamus *Dictionaries*
=========================

Tipe data lain yang berguna yang dibangun ke dalam Python adalah
*dictionary* (lihat Mapping Types --- dict). Kamus *dictionary*
kadang-kadang ditemukan dalam bahasa lain sebagai "assosiative
memories" atau "assosiative array". Tidak seperti urutan *sequences*,
yang diindeks oleh sejumlah angka, kamus *dictionary* diindeks oleh
*keys*, yang dapat berupa jenis apa pun yang tidak dapat diubah
*immutable type*; string dan angka selalu bisa menjadi kunci *key*.
*Tuples* dapat digunakan sebagai kunci jika hanya berisi string,
angka, atau *tuple*; jika sebuah tuple berisi objek yang bisa berubah
baik secara langsung atau tidak langsung, itu tidak dapat digunakan
sebagai kunci *key*. Anda tidak dapat menggunakan daftar *list*
sebagai kunci, karena daftar dapat dimodifikasi di tempat menggunakan
penugasan indeks, penugasan *slice*, atau metode seperti "append()"
dan "extend()".

It is best to think of a dictionary as an unordered set of *key:
value* pairs, with the requirement that the keys are unique (within
one dictionary). A pair of braces creates an empty dictionary: "{}".
Placing a comma-separated list of key:value pairs within the braces
adds initial key:value pairs to the dictionary; this is also the way
dictionaries are written on output.

Operasi utama pada kamus *dictionary* adalah menyimpan nilai dengan
beberapa kunci *key* dan mengekstraksi nilai yang diberikan kunci
*key*. Dimungkinkan juga untuk menghapus pasangan kunci:nilai dengan
"del". Jika Anda menyimpan menggunakan kunci yang sudah digunakan,
nilai lama yang terkait dengan kunci itu dilupakan. Merupakan
kesalahan untuk mengekstraksi nilai menggunakan kunci yang tidak ada.

The "keys()" method of a dictionary object returns a list of all the
keys used in the dictionary, in arbitrary order (if you want it
sorted, just apply the "sorted()" function to it).  To check whether a
single key is in the dictionary, use the "in" keyword.

Ini adalah contoh kecil menggunakan kamus *dictionary*:

   >>> tel = {'jack': 4098, 'sape': 4139}
   >>> tel['guido'] = 4127
   >>> tel
   {'sape': 4139, 'guido': 4127, 'jack': 4098}
   >>> tel['jack']
   4098
   >>> del tel['sape']
   >>> tel['irv'] = 4127
   >>> tel
   {'guido': 4127, 'irv': 4127, 'jack': 4098}
   >>> tel.keys()
   ['guido', 'irv', 'jack']
   >>> 'guido' in tel
   True

Pembangun *constructor* "dict()" membangun kamus langsung dari urutan
pasangan kunci-nilai:

   >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
   {'sape': 4139, 'jack': 4098, 'guido': 4127}

Selain itu, pemahaman kamus *dict comprehensions* dapat digunakan
untuk membuat kamus *dictionary* dari ekspresi kunci dan nilai acak
*arbitrary*:

   >>> {x: x**2 for x in (2, 4, 6)}
   {2: 4, 4: 16, 6: 36}

Ketika kunci adalah string sederhana, kadang-kadang lebih mudah untuk
menentukan pasangan menggunakan argumen kata kunci *keyword
arguments*:

   >>> dict(sape=4139, guido=4127, jack=4098)
   {'sape': 4139, 'jack': 4098, 'guido': 4127}


5.6. Teknik Perulangan
======================

Saat mengulang melalui urutan, indeks posisi dan nilai terkait dapat
diambil pada saat yang sama menggunakan fungsi "enumerate()".

   >>> for i, v in enumerate(['tic', 'tac', 'toe']):
   ...     print i, v
   ...
   0 tic
   1 tac
   2 toe

Untuk mengulang dua urutan atau lebih secara bersamaan, entri dapat
dipasangkan dengan fungsi "zip()".

   >>> questions = ['name', 'quest', 'favorite color']
   >>> answers = ['lancelot', 'the holy grail', 'blue']
   >>> for q, a in zip(questions, answers):
   ...     print 'What is your {0}?  It is {1}.'.format(q, a)
   ...
   What is your name?  It is lancelot.
   What is your quest?  It is the holy grail.
   What is your favorite color?  It is blue.

Untuk mengulang urutan secara terbalik, pertama tentukan urutan dalam
arah maju dan kemudian panggil fungsi "reversed()".

   >>> for i in reversed(xrange(1,10,2)):
   ...     print i
   ...
   9
   7
   5
   3
   1

Untuk mengulangi sebuah urutan *sequence* dalam susunan yang
diurutkan, gunakan fungsi "sort()" yang mengembalikan daftar terurut
baru dengan membiarkan sumber tidak diubah.

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> for f in sorted(set(basket)):
   ...     print f
   ...
   apple
   banana
   orange
   pear

When looping through dictionaries, the key and corresponding value can
be retrieved at the same time using the "iteritems()" method.

   >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
   >>> for k, v in knights.iteritems():
   ...     print k, v
   ...
   gallahad the pure
   robin the brave

Terkadang tergoda untuk mengubah daftar *list* saat Anda
mengulanginya; namun, seringkali lebih mudah dan aman untuk membuat
daftar *list* baru.

   >>> import math
   >>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
   >>> filtered_data = []
   >>> for value in raw_data:
   ...     if not math.isnan(value):
   ...         filtered_data.append(value)
   ...
   >>> filtered_data
   [56.2, 51.7, 55.3, 52.5, 47.8]


5.7. Lebih lanjut tentang Kondisi
=================================

Kondisi yang digunakan dalam pernyataan "while" dan "if" dapat berisi
operator apa pun, bukan hanya perbandingan.

Operator perbandingan "in" dan "not in" memeriksa apakah suatu nilai
terjadi (tidak terjadi) secara berurutan. Operator "is" dan "is not"
membandingkan apakah dua objek benar-benar objek yang sama; ini hanya
penting untuk objek yang dapat diubah seperti daftar *list*. Semua
operator pembanding memiliki prioritas yang sama, yang lebih rendah
daripada semua operator numerik.

Perbandingan bisa dibuat berantai. Sebagai contoh, "a < b == c"
menguji apakah "a" kurang dari "b" dan apa "b" sama dengan "c".

Perbandingan dapat digabungkan menggunakan operator Boolean "and" dan
"or", dan hasil perbandingan (atau ekspresi Boolean lainnya) dapat
dinegasikan dengan "not". Ini memiliki prioritas lebih rendah daripada
operator pembanding; di antara mereka, "not" memiliki prioritas
tertinggi dan "or" terendah, sehingga "A and not B or C" setara dengan
"(A and (not B)) or C" . Seperti biasa, tanda kurung dapat digunakan
untuk mengekspresikan komposisi yang diinginkan.

Operator Boolean "and" dan "or" disebut operator *short-circuit*:
argumen mereka dievaluasi dari kiri ke kanan, dan evaluasi berhenti
segera setelah hasilnya ditentukan. Misalnya, jika "A" dan "C"
bernilai benar tetapi "B" salah, "A and B and C" tidak mengevaluasi
ekspresi "C". Ketika digunakan sebagai nilai umum dan bukan sebagai
Boolean, nilai kembalian dari operator hubung singkat *short-circuit*
adalah argumen terakhir yang dievaluasi.

Dimungkinkan untuk menetapkan hasil perbandingan atau ekspresi Boolean
lainnya ke variabel. Sebagai contoh,

   >>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
   >>> non_null = string1 or string2 or string3
   >>> non_null
   'Trondheim'

Perhatikan bahwa dalam Python, tidak seperti C, pemberian nilai
*assignment* tidak dapat terjadi di dalam ekspresi. Pemrogram C
mungkin menggerutu tentang hal ini, tetapi ini menghindari kelas umum
masalah yang ditemukan dalam program C: mengetikkan "=" dalam ekspresi
ketika "==" dimaksudkan.


5.8. Membandingkan Urutan *Sequences* dan Jenis Lainnya
=======================================================

Sequence objects may be compared to other objects with the same
sequence type. The comparison uses *lexicographical* ordering: first
the first two items are compared, and if they differ this determines
the outcome of the comparison; if they are equal, the next two items
are compared, and so on, until either sequence is exhausted. If two
items to be compared are themselves sequences of the same type, the
lexicographical comparison is carried out recursively.  If all items
of two sequences compare equal, the sequences are considered equal. If
one sequence is an initial sub-sequence of the other, the shorter
sequence is the smaller (lesser) one.  Lexicographical ordering for
strings uses the ASCII ordering for individual characters.  Some
examples of comparisons between sequences of the same type:

   (1, 2, 3)              < (1, 2, 4)
   [1, 2, 3]              < [1, 2, 4]
   'ABC' < 'C' < 'Pascal' < 'Python'
   (1, 2, 3, 4)           < (1, 2, 4)
   (1, 2)                 < (1, 2, -1)
   (1, 2, 3)             == (1.0, 2.0, 3.0)
   (1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

Note that comparing objects of different types is legal.  The outcome
is deterministic but arbitrary: the types are ordered by their name.
Thus, a list is always smaller than a string, a string is always
smaller than a tuple, etc. [1] Mixed numeric types are compared
according to their numeric value, so 0 equals 0.0, etc.

-[ Catatan kaki ]-

[1] The rules for comparing objects of different types should not
    be relied upon; they may change in a future version of the
    language.
