Autor Zpráva
PHP_ucednik
Profil *
Ahoj, potřebova bych poradit jak co nejeelegatněji přeskládat PHP pole na požadovou podobu. Zkoušel jsem, ale nejde mi to, uplně jsem se do toho zamotal :-(.


Pole vypadá takhle:

$arr[] = ['articleId' => 1, 'commentId' => 10];
$arr[] = ['articleId' => 2, 'commentId' => 20];
$arr[] = ['articleId' => 1, 'commentId' => 30];
$arr[] = ['articleId' => 2, 'commentId' => 40];
$arr[] = ['articleId' => 3, 'commentId' => 50];

a potřeboval bych ho takhle:

Array
(
    [0] => Array
        (
            [articleId] => 1
            [comments] => Array
                (
                    [0] => Array
                        (
                            [commentId] => 10
                        )

                    [1] => Array
                        (
                            [commentId] => 30
                        )

                )

        )

    [1] => Array
        (
            [articleId] => 2
            [comments] => Array
                (
                    [0] => Array
                        (
                            [commentId] => 20
                        )

                    [1] => Array
                        (
                            [commentId] => 40
                        )

                )

        )

    [2] => Array
        (
            [articleId] => 3
            [comments] => Array
                (
                    [0] => Array
                        (
                            [commentId] => 50
                        )

                )

        )

)

Je to zjednodušené, určitě to jde nějak snadno a fikaně, díky.
Lonanek
Profil
PHP_ucednik:
Zkoušel jsem, ale nejde mi to
A co jste zkoušel?

Váš dotaz bych zařadil do kategorie Něco chci, ale nevím co.
Jak vypadá vstupní pole?
Jaká je požadovaná podoba?
Do čeho jste se zamotal?

třeba arsort()
PHP_ucednik
Profil *
Vždyt jsem Vám vstupní podobu a výstupní ukázal, zkoušel jsem uložení jen articleId a k nim jsem přes další funkci dohledával komentáře (2x samostatné průchody a ten druhý na dohledání bylo m*n průchodů, byla to taková sra***, že jsem to radši smazal :(
Rfilip
Profil
Dá se to udělat jedním cyklem, pro každý prvek se podíváš jestli v novém poli daný article id existuje, pokud ne, přidáš ho tam. V obou případech vložíš comment id do toho vnitřního pole
Keeehi
Profil
PHP_ucednik:
Nemohly by ty IDčka být indexy těch polí? Protože by to hodně pomohlo. Pokud ne, tak bude nejspíše potřeba to zdrojové pole seřadit (pokud to jde z databáze tak už nejlépe tam) protože se jinak bude muset vyhledávat v tom výsledném poli a pravděpodobně to bude pomalé. Při seřazeném vstupním poli to půjde konstruovat bez vyhledávání. Jak jsem ale psal hned na začátku, celému tomuhle se dá vyhnout, pokud IDčka budou indexy.
PHP_ucednik
Profil *
Rfilip:
To bych tedy chtěl vidět.

Keeehi
Bohužel, data dostanu takto a potřebuji je do jiné služby odeslat tak jak jsem postnul na začátku.

Nakonec jsem vymyslel tohle, ale nijak kratke ani efektni to neni, nic lepsiho uz me nenapada, ale funguje to.

<?


// 1 vstupni data
$arr[] = ['articleId' => 1, 'commentId' => 10];
$arr[] = ['articleId' => 2, 'commentId' => 20];
$arr[] = ['articleId' => 1, 'commentId' => 30];
$arr[] = ['articleId' => 2, 'commentId' => 40];
$arr[] = ['articleId' => 3, 'commentId' => 50];


// preulozeni na indexy podle ID clanku, tj sdruzeni
$arr2 = [];
foreach ($arr as $row)
{
    $arr2[$row['articleId']][] = $row['commentId'];
}    


// podoba kterou potrebuji
$arr3 = [];
$i = 0;
foreach ($arr2 as $articleId => $row)
{
    $arr3[$i]['articleId'] = $articleId;
    $arr3[$i]['comments'] = [];
    foreach ($row as $comment)
    {

        $arr3[$i]['comments'][] = ['commentId' => $comment];
    }

    $i++;
}


echo "<pre>" . print_r($arr3, TRUE) . "</pre>";
Keeehi
Profil
S tím srovnáním by to vypadalo takto:
<?php
$arr[] = ['articleId' => 1, 'commentId' => 10];
$arr[] = ['articleId' => 2, 'commentId' => 20];
$arr[] = ['articleId' => 1, 'commentId' => 30];
$arr[] = ['articleId' => 2, 'commentId' => 40];
$arr[] = ['articleId' => 3, 'commentId' => 50];
 
usort($arr, function($a, $b) { return $a['articleId'] > $b['articleId']; });

$lastId = null;
foreach ($arr as $row) {
    if ($lastId !== $row['articleId']) {
        if(isset($article)) {
            $result[] = $article;
        }
        $article = ['articleId' => $row['articleId']];
    }
    
    $article['comments'][] = ['commentId' => $row['commentId']];
    
    $lastId = $row['articleId'];
}
if(isset($article)) {
    $result[] = $article;
}
 
echo "<pre>" . print_r($result, TRUE) . "</pre>";



Nebo verze s forem, která vypadá trochu lépe, jelikož je možné se rozhlížet v poli kolem sebe.
<?php
$arr[] = ['articleId' => 1, 'commentId' => 10];
$arr[] = ['articleId' => 2, 'commentId' => 20];
$arr[] = ['articleId' => 1, 'commentId' => 30];
$arr[] = ['articleId' => 2, 'commentId' => 40];
$arr[] = ['articleId' => 3, 'commentId' => 50];
 
usort($arr, function($a, $b) { return $a['articleId'] > $b['articleId']; });

for ($i = 0, $length = count($arr); $i < $length; $i++) {
    if ($i === 0 || $arr[$i-1]['articleId'] !== $arr[$i]['articleId']) {
        $article = ['articleId' => $arr[$i]['articleId']];
    }
    
    $article['comments'][] = ['commentId' => $arr[$i]['commentId']];
    
    if ($i === $length -1 || $arr[$i]['articleId'] !== $arr[$i+1]['articleId']) {
        $result[] = $article;
    }
}
 
echo "<pre>" . print_r($result, TRUE) . "</pre>";
Alphard
Profil
Já bych se nebál konstruovat to pomocí ideček a pak klíče resetovat.
$res = [];
foreach ($arr as $item) {
  $res[$item['articleId']]['articleId'] = $item['articleId'];
  $res[$item['articleId']]['comments'][] = ['commentId' => $item['commentId']];
}
$res = array_values($res);

Kdo má velký problém smířit se s tím, že jsem tam nedal if (!isset(..)), nechť si to doplní :-)
PHP_ucednik
Profil *
Keehi, Alphard: Díky oboum, oba postupy jsou zajímavé. Je jasné, že Alphardův je kratší a čitelnější, u Keehiho je zajímavá co vlastně existuje a postupné ukládání. Uložím si oboje, moc díky.
Keeehi
Profil
PHP_ucednik:
Měřené to nemám, ale Alphardův kód by měl být asi rychlejší. Nemá tam to řazení které má složitost O(n*log n). Projeví se to ale až při opravdu velkém počtu záznamů.

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: