Daftar produk yang tumbuh dari sepuluh menjadi seratus membuat daftar yang polos kehilangan daya guna: pengguna butuh menemukan, menyaring, dan mengurutkan, bukan sekadar melihat. Bagian ini menambahkan tiga kemampuan itu ke class Inventaris — dan ketiganya berbagi sifat yang sama dengan seluruh desain proyek ini: function murni yang menerima kriteria dan mengembalikan hasil baru, tanpa mengubah data asal. Pola copy-then-transform ini membuat operasi baca aman dipanggil kapan saja, bahkan dari test harness yang membandingkan urutan asli dan hasil urutan dalam satu pernyataan.
Pencarian Nama yang Tidak Peka Huruf Besar #
Pengguna tidak bisa dipaksa mengingat kapitalisasi persis: kopi, KOPI, dan Kopi harus sama-sama menemukan produk. Normalisasi ke huruf kecil kita lakukan di dua sisi — pada kata kunci dan pada nama produk — lewat satu helper:
std::string keHurufKecil(std::string_view teks) {
std::string hasil;
hasil.reserve(teks.size());
for (char c : teks) {
hasil.push_back(
static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
}
return hasil;
}
// pencarian nama: tidak peka huruf besar/kecil, pola boleh sebagian nama
std::vector<Produk> cariNama(std::string_view kataKunci) const {
const std::string kunci = keHurufKecil(kataKunci);
std::vector<Produk> hasil;
for (const Produk& p : produk_) {
if (keHurufKecil(p.nama).find(kunci) != std::string::npos) {
hasil.push_back(p);
}
}
return hasil;
}Dua detail teknis di sini sering terlewat. Pertama, std::tolower menerima int, dan memberikan char yang bernilai negatif — mungkin pada karakter non-ASCII — adalah undefined behavior; static_cast<unsigned char> sebelum pemanggilan memangkas masalah itu di akar. Kedua, pencarian memakai std::string::find, jadi gul menemukan Gula: kata kunci boleh sebagian nama, bukan harus sama persis. Loop manual di cariNama sengaja dipakai alih-alih std::copy_if supaya pemanggilan keHurufKecil(p.nama) — yang membutuhkan variabel sementara — tetap terbaca; di section berikutnya Anda melihat versi copy_if untuk kasus yang lebih sederhana.
Filter Stok dengan std::copy_if #
Kebutuhan klasik inventaris: produk mana yang persediaannya menipis? filterStok menjawabnya dengan algoritma STL standar:
std::vector<Produk> filterStok(int minimum) const {
std::vector<Produk> hasil;
std::copy_if(produk_.begin(), produk_.end(),
std::back_inserter(hasil),
[minimum](const Produk& p) { return p.stok >= minimum; });
return hasil;
}std::copy_if menyalin hanya elemen yang lolos predikat, dan std::back_inserter membuat vector tujuan tumbuh otomatis — kita tidak perlu tahu ukuran hasilnya di depan. Lambda menangkap minimum lewat capture by value: kriteria tersalin ke dalam lambda, sehingga predikatnya stateless terhadap dunia luar dan aman untuk pola pemikiran apa pun yang kelak menggantikan copy_if. Bandingkan dengan cariNama: kebutuhan yang sama — pilah elemen yang lolos — dengan gaya yang berbeda karena ada transformasi perantara; memilih gaya per kasus, bukan memaksakan satu pola, adalah bagian dari kematangan.
Pengurutan yang Aman dan Deterministik #
Komponen ketiga adalah urut dengan tiga pilihan bidang yang dikemas sebagai enum:
enum class Urutkan { Harga, Nama, Stok };
std::vector<Produk> urut(Urutkan bidang) const {
std::vector<Produk> hasil = produk_;
switch (bidang) {
case Urutkan::Harga:
std::sort(hasil.begin(), hasil.end(),
[](const Produk& a, const Produk& b) {
if (a.harga != b.harga) return a.harga < b.harga;
return a.kode < b.kode; // penentu seri
});
break;
case Urutkan::Stok:
std::sort(hasil.begin(), hasil.end(),
[](const Produk& a, const Produk& b) {
if (a.stok != b.stok) return a.stok < b.stok;
return a.kode < b.kode;
});
break;
case Urutkan::Nama:
std::sort(hasil.begin(), hasil.end(),
[](const Produk& a, const Produk& b) {
int urut = keHurufKecil(a.nama)
.compare(keHurufKecil(b.nama));
if (urut != 0) return urut < 0;
return a.kode < b.kode;
});
break;
}
return hasil;
}Tiga keputusan desain menopang method ini. Pertama, urut menyalin seluruh vector sebelum mengurutkan — urutan asli terselamatkan, dan daftar setelah urut apa pun tetap menunjukkan urutan masuk; perilaku ini diuji eksplisit di Bagian 5. Kedua, setiap komparator punya tie-breaker kode: bila harga (atau stok, atau nama) sama, perbandingan jatuh ke kode produk. Alasannya bukan estetika — std::sort tidak stabil, jadi dua elemen yang setara bisa tercetak dalam urutan berbeda antar eksekusi; penentu seri membuat output deterministik, syarat mutlak untuk semua contoh yang diuji. Ketiga, perbandingan nama memakai keHurufKecil di kedua sisi sehingga kopi dan Kopi diperlakukan setara juga dalam pengurutan.
Mencoba Ketiganya Sekaligus #
Kompilasi lalu jalankan sesi yang mencakup pencarian, filter, dan ketiga pengurutan:
g++ -std=c++23 -Wall -Wextra inventaris.cpp -o inventaris
printf 'tambah P001 Kopi 15000 20\ntambah P002 Gula 12000 5\ntambah P003 Pensil 3000 100\ncari kopi\ncari KOPI\ncari gul\ncari coklat\nfilter 50\nurut harga\nurut nama\nurut stok\n' | ./inventarisOutput yang Dihasilkan:
ditambahkan: P001 (Kopi)
ditambahkan: P002 (Gula)
ditambahkan: P003 (Pensil)
KODE NAMA HARGA STOK
P001 Kopi 15000 20
KODE NAMA HARGA STOK
P001 Kopi 15000 20
KODE NAMA HARGA STOK
P002 Gula 12000 5
tidak ada produk yang cocok dengan 'coklat'
KODE NAMA HARGA STOK
P003 Pensil 3000 100
KODE NAMA HARGA STOK
P003 Pensil 3000 100
P002 Gula 12000 5
P001 Kopi 15000 20
KODE NAMA HARGA STOK
P002 Gula 12000 5
P001 Kopi 15000 20
P003 Pensil 3000 100
KODE NAMA HARGA STOK
P002 Gula 12000 5
P001 Kopi 15000 20
P003 Pensil 3000 100
selesai.Baca outputnya sebagai bukti tiap keputusan: kopi dan KOPI sama-sama menemukan satu produk; gul menemukan Gula lewat pencarian sebagian; coklat menghasilkan daftar kosong dengan pesan yang jelas, bukan galat. filter 50 hanya meloloskan Pensil. urut harga mengurutkan menaik — 3000, 12000, 15000 — dan urut nama serta urut stok kebetulan menghasilkan urutan yang sama untuk data ini karena nama dan stok kebetulan searah; dengan data berbeda, keduanya bisa memisah. Yang tidak terlihat di layar justru penting: setelah semua operasi, daftar tanpa argumen tetap menampilkan urutan masuk P001, P002, P003.
Pencarian dan pengurutan membuat data mudah dibaca, tetapi semua itu masih hidup di memori: begitu program berakhir, semuanya hilang. Bagian 4 memberi data tempat tinggal permanen di berkas.
Rujukan resmi: std::copy_if (cppreference) , std::sort (cppreference) .