Autor Zpráva
Bobeš
Profil *
Zdravíčko,
poradí mi někdo jak opakovaně vybrat prvky na n-té pozici v poli. Řekněme, že mám pole o obsahu zhruba několik set prvků a potřebuju vyfiltrovat třebas každý čtvrtý, osmý, dvanáctý... atakdále prvek a ty pak vložit do jiného pole bo řetězce k dalšímu zpracování. Ať hledám, jak hledám...
ShiraNai7
Profil
// testovaci pole
$pole = array();
for($i = 1; $i <= 100; ++$i) $pole[] = $i;

// funkce
function arrayGetNth($arr, $n)
{
  $output = array();
  $arr_size = sizeof($arr);
  $i = $n - 1;
  while($i < $arr_size) {
    $sl = array_slice($arr, $i, 1);
    $output[] = $sl[0];
    $i += $n;
  }
  return $output;
}

// test
print_r(arrayGetNth($pole, 4)); // kazdy 4ty prvek


Vysledkem je:

Array
(
    [0] => 4
    [1] => 8
    [2] => 12
    [3] => 16
    [4] => 20
    [5] => 24
    [6] => 28
    [7] => 32
    [8] => 36
    [9] => 40
    [10] => 44
    [11] => 48
    [12] => 52
    [13] => 56
    [14] => 60
    [15] => 64
    [16] => 68
    [17] => 72
    [18] => 76
    [19] => 80
    [20] => 84
    [21] => 88
    [22] => 92
    [23] => 96
    [24] => 100
)
Majkl578
Profil
[#2] ShiraNai7:
To je poměrně nešikovná funkce provádějící zbytečné (ne-li nesmyslné) úkony.

Existují i jednodušší a transparentnější řešení, například:
$data = range(50, 1000, 5); // vstupní data
$step = 4; // krokování

$selector = function (array $array, $step) {
    $i = 0;
    return array_filter($array, function ($item) use ($step, &$i) {
        return ++$i % $step === 0;
    });
};

var_dump($selector($data, $step)); //4., 8., 12. atd.
ShiraNai7
Profil
Majkl578:
To je poměrně nešikovná funkce provádějící zbytečné (ne-li nesmyslné) úkony.

Výsledek je stejný, co je na tom nesmyslného?
Majkl578
Profil
ShiraNai7:
Celý ten while cyklus dělá zbytečné úkony, konkrétně řádky 12 a 13 jsou zbytečný nesmysl. Nehledě na to, že tvé řešení nezohledňuje původní klíče ve výsledku (což sice nemusí být nutné, ale rozhodně je to vhodné).
ShiraNai7
Profil
Majkl578:
Celý ten while cyklus dělá zbytečné úkony, konkrétně řádky 12 a 13 jsou zbytečný nesmysl.

Jak jinak bez funkce array_filter vybrat ntý prvek z pole (které může obsahovat číselné i jiné indexy)? Nijak. A nepředpokádám že Bobeš používá verzi PHP 5.4+ kde bych mohl úplně vynechat přiřazování ( $output[] = array_slice($arr, $i, 1)[0]; )
joe
Profil
Nelíbí se mi ani jedno řešení, proto přidávám moje, které je zároveň nejrychlejší ze zde uvedených (zatím jsem se moc nezžil s používáním closures v PHP) a nevím proč dělat věci složitě, když to jde jednoduše :)

function arrayNth(array $array, $n) {
	$output = array();
	$i = 0;
	foreach($array as $key => $value) {
		if(++$i % $n === 0) $output[$key] = $value;
	}
	return $output;
}


ShiraNai7:
Výsledek je stejný
Výsledek asi stejný bude, ale to tvé řešení pokulhává už při 100000 záznamech v poli.
ShiraNai7
Profil
joe:
Moc rychlé to asi nebude, proč mě nenapadl obyčejný foreach nevím, možná protože bylo půl jedné ráno :)
Bobeš
Profil *
Díky za řešení pánové ;-)
Majkl578
Profil
Dobře tedy, když jsme už se dostali ke srovnávání složitosti, porovnal jsem jednotlivé funkce.
Použil jsem totožný script na 20 tisíc stejných záznamů v poli nechal vypsat čas a maximum užité paměti:
$data = range(1, 2e4);

$start = microtime(TRUE);

// funkce
// a volání funkce

echo microtime(TRUE) - $start;
echo PHP_EOL;
echo memory_get_peak_usage();
echo PHP_EOL;

Výsledky jsou následující:
ShiraNai7: 5.301s, 3.576 MB
Majkl578: 0.174s, 3.577 MB
joe: 0.068s, 5.307 MB

ShiraNai7 zde může vidět, proč je jeho řešení naprosto nepoužitelné. Řešení od joa je sice nejrychlejší, nicméně o 2/3 paměťově náročnější.
joe
Profil
Majkl578:
To je zajímavý :) Tak jsem se aspoň trochu poučil, díky. Ale nějak nechápu proč ten foreach zabere víc paměti než ten array_filter, co vlastně taky prochází celé to pole, ne?

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0