Kolekce — Pole a listy: protože data se sama nesrovnají
Toto je třetí díl série! Předchozí díl najdeš zde.
Pole je nejzákladnější datová struktura, kterou budeš v životě používat. Máš seznam věcí — uživatelů, produktů, čísel — a potřebuješ z nich něco vytáhnout. Vyfiltrovat, seřadit, transformovat, agregovat. Každý jazyk to umí, ale každý jazyk to dělá po svém.
Zadání je jednoduché. Máme seznam uživatelů:
| Jméno | Věk | Aktivní |
|---|---|---|
| Alice | 30 | ano |
| Bob | 25 | ne |
| Charlie | 35 | ano |
| Diana | 28 | ano |
| Eve | 22 | ne |
Chceme:
- Vyfiltrovat pouze aktivní uživatele
- Seřadit je podle jména
- Vypsat jejich jména
- Vypsat průměrný věk aktivních uživatelů
1. C++
#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
struct User
{
std::string name;
int age;
bool active;
};
int main()
{
std::vector<User> users = {
{"Alice", 30, true},
{"Bob", 25, false},
{"Charlie", 35, true},
{"Diana", 28, true},
{"Eve", 22, false},
};
std::vector<User> active;
std::copy_if(users.begin(), users.end(), std::back_inserter(active),
[](const User& u) { return u.active; });
std::sort(active.begin(), active.end(),
[](const User& a, const User& b) { return a.name < b.name; });
for (size_t i = 0; i < active.size(); i++) {
std::cout << active[i].name;
if (i < active.size() - 1) std::cout << ", ";
}
std::cout << std::endl;
double avg = std::accumulate(active.begin(), active.end(), 0.0,
[](double sum, const User& u) { return sum + u.age; }) / active.size();
std::cout << "Průměrný věk: " << avg << std::endl;
return 0;
}
C++ přistupuje ke kolekcím přes iterátory a STL algoritmy. std::copy_if filtruje, std::sort řadí,
std::accumulate počítá součet. Vše s lambdami. Na papíře funkcionální, v praxi je to jako psát básničku
pomocí slovníku — každé slovo je správně, ale celkový dojem bolí.
Přehlednost: 2/10
Počet řádků: 42
2. C#
using System;
using System.Collections.Generic;
using System.Linq;
class User
{
public string Name { get; set; }
public int Age { get; set; }
public bool Active { get; set; }
}
class Program
{
static void Main()
{
var users = new List<User>
{
new User { Name = "Alice", Age = 30, Active = true },
new User { Name = "Bob", Age = 25, Active = false },
new User { Name = "Charlie", Age = 35, Active = true },
new User { Name = "Diana", Age = 28, Active = true },
new User { Name = "Eve", Age = 22, Active = false },
};
var active = users
.Where(u => u.Active)
.OrderBy(u => u.Name)
.ToList();
Console.WriteLine(string.Join(", ", active.Select(u => u.Name)));
Console.WriteLine($"Průměrný věk: {active.Average(u => u.Age):0.0}");
}
}
LINQ je jedna z nejhezčích věcí, co C# má. .Where(), .OrderBy(), .Select(), .Average() — čteš to
jako větu. Definice třídy User je upovídaná (každá property na třech řádcích), ale samotné zpracování
dat je ukázkové. Tohle je přesně to, jak by funkcionální API mělo vypadat. Nicméně i tam C# dostal -2 body
za upovídanost.
Přehlednost: 8/10
Počet řádků: 33
3. Java
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class User
{
String name;
int age;
boolean active;
User(String name, int age, boolean active)
{
this.name = name;
this.age = age;
this.active = active;
}
}
class Main
{
public static void main(String[] args)
{
List<User> users = Arrays.asList(
new User("Alice", 30, true),
new User("Bob", 25, false),
new User("Charlie", 35, true),
new User("Diana", 28, true),
new User("Eve", 22, false)
);
List<User> active = users.stream()
.filter(u -> u.active)
.sorted(Comparator.comparing(u -> u.name))
.collect(Collectors.toList());
System.out.println(active.stream()
.map(u -> u.name)
.collect(Collectors.joining(", ")));
double avg = active.stream()
.mapToInt(u -> u.age)
.average()
.orElse(0);
System.out.printf("Průměrný věk: %.1f%n", avg);
}
}
Java Stream API dělá vše správně, ale s charakteristickou upovídaností. Collectors.toList(),
Collectors.joining(), mapToInt(), .average().orElse(0) — každá operace má svůj vlastní
ceremoniál. Výsledek je čitelný pokud Javu znáš, ale pro nováčka je to hodně nových pojmů najednou.
Přehlednost: 6/10
Počet řádků: 47
4. Rust
struct User
{
name: &'static str,
age: u32,
active: bool,
}
fn main()
{
let users = vec![
User { name: "Alice", age: 30, active: true },
User { name: "Bob", age: 25, active: false },
User { name: "Charlie", age: 35, active: true },
User { name: "Diana", age: 28, active: true },
User { name: "Eve", age: 22, active: false },
];
let mut active: Vec<&User> = users.iter()
.filter(|u| u.active)
.collect();
active.sort_by_key(|u| u.name);
println!("{}", active.iter().map(|u| u.name).collect::<Vec<_>>().join(", "));
let avg = active.iter().map(|u| u.age).sum::<u32>() as f64 / active.len() as f64;
println!("Průměrný věk: {}", avg);
}
Rust iterátorové API je kompaktní, ale stále plné specifik jazyka. Vec<&User> (vektor referencí),
collect::<Vec<_>>() (turbofish syntax pro specifikaci typu), sum::<u32>(), as f64 — každé z toho
dává smysl v kontextu Rustu, ale dohromady to vytváří čtení, které vyžaduje soustředění. Na rozdíl od
předchozích dílů série se zde Rust drží o něco lépe — iterátorové metody jako .filter() a .map()
jsou čitelné.
Přehlednost: 4/10
Počet řádků: 28
5. JavaScript
const users = [
{ name: "Alice", age: 30, active: true },
{ name: "Bob", age: 25, active: false },
{ name: "Charlie", age: 35, active: true },
{ name: "Diana", age: 28, active: true },
{ name: "Eve", age: 22, active: false },
];
const active = users
.filter(u => u.active)
.sort((a, b) => a.name.localeCompare(b.name));
console.log(active.map(u => u.name).join(", "));
const avg = active.reduce((sum, u) => sum + u.age, 0) / active.length;
console.log(`Průměrný věk: ${avg}`);
JavaScript array metody jsou přesně to, co by funkcionální API mělo být. .filter(), .sort(),
.map(), .reduce() — vše řetězitelné, přirozené, čitelné. Žádné importy, žádné třídy, žádný
ceremoniál. Prostě data a operace nad nimi.
Přehlednost: 9/10
Počet řádků: 16
6. Python
users = [
{"name": "Alice", "age": 30, "active": True},
{"name": "Bob", "age": 25, "active": False},
{"name": "Charlie", "age": 35, "active": True},
{"name": "Diana", "age": 28, "active": True},
{"name": "Eve", "age": 22, "active": False},
]
active = sorted(
filter(lambda u: u["active"], users),
key=lambda u: u["name"]
)
print(", ".join(u["name"] for u in active))
avg = sum(u["age"] for u in active) / len(active)
print(f"Průměrný věk: {avg}")
Python je opět čistý a přirozený. Generator expressions (u["name"] for u in active) jsou elegantní
zkratka pro map. Jedinou výtkou je, že filter() vrací iterátor, takže ho musíš obalit do sorted() —
trochu neintuitivní pořadí operací oproti .filter().sort() řetězci v jiných jazycích, za což ztrácí
3 body.
Přehlednost: 7/10
Počet řádků: 17
7. PHP
<?php
$users = [
["name" => "Alice", "age" => 30, "active" => true],
["name" => "Bob", "age" => 25, "active" => false],
["name" => "Charlie", "age" => 35, "active" => true],
["name" => "Diana", "age" => 28, "active" => true],
["name" => "Eve", "age" => 22, "active" => false],
];
$active = array_filter($users, fn(array $u): bool => $u["active"]);
usort($active, fn(array $a, array $b): int => $a["name"] <=> $b["name"]);
echo implode(", ", array_column($active, "name")) . "\n";
$avg = array_sum(array_column($active, "age")) / count($active);
echo "Průměrný věk: $avg\n";
PHP má pro práci s poli celou sadu array_* funkcí. array_filter(), array_column(),
array_sum() — každá dělá přesně to, co říká. usort() s strcmp() je trochu staromódní,
ale funkční. Celkově je kód přehledný, i když postrádá elegantní řetězení jako JavaScript nebo C#.
Přehlednost: 8/10
Počet řádků: 16
Závěr
| Jazyk | Přehlednost | Počet řádků |
|---|---|---|
| C++ | 2/10 | 42 |
| C# | 8/10 | 33 |
| Java | 6/10 | 47 |
| Rust | 4/10 | 28 |
| JavaScript | 9/10 | 16 |
| Python | 7/10 | 17 |
| PHP | 8/10 | 16 |
Vítěz v přehlednosti je jednoznačně JavaScript — čisté řetězení bez importů, bez tříd, bez zbytečností. Těsně za ním sdílejí druhé místo C# a PHP s 8/10, každý jiným způsobem.
V počtu řádků vede JavaScript a PHP na 16 řádcích, Python je těsně za nimi na 17. Na opačném konci se bijí o poslední místo Java (47 řádků) a C++ (42 řádků) — dvě jazyky, které pro jednoduché zpracování pole vyžadují více infrastruktury než samotné řešení.
Rust se vejde na 28 řádků, ale při přehlednosti 4/10 je to jen méně katastrofální výsledek — ne vítězství. Jako kdybys chválil někoho za to, že místo hodiny se mu úloha podařila za půl hodiny, ale stále ji vyřešil špatně.
Tak užívej a já jdu pouštět vodu z pramenů.