Search code examples
phphtmlarraysformsflat-file

Spliting .txt file lines in to multi-layered array key value pairs then sorting it


Since this question has a long explanation, I'll ask the question, then have the explanation below -- Can you sort a multidimensional array by their internal array key value, or is there a better way to get around sorting key value pairs that will have inevitable duplicates, than just using an array?

I am mostly unfamiliar with using PHP and want to learn how to store data.

The very simple example I made is just two HTML form inputs for a score and a name and a PHP file to handle the input to be stored in a plain .txt file, which was originally written with the pattern

42|John
32|Jane
25|John

I was able to successfully split the data, sort it, add the new inputted values then store it all back in the text file to be displayed somewhere else, using the name as the key and the score as the value.

I did all this only to realize that it would only store sort and display the last value associated with each name (i.e.)

42|John
32|Jane
25|John

would be sorted to

32|Jane
25|John

because you, obviously, can't have two of the same keys in an array, which is something I completely overlooked.

My solution, currently is to have an extra number that is unique to each name/score pair, which I formatted in the text file as

1|42|John
2|32|Jane
3|25|John

I then split them into a multidimensional array using this foreach loop

foreach($arr as $key => $value) {
  $lineData = explode("|", $value);
  $scores[$lineData[0]] = array($lineData[1] => $lineData[2]);
}

To get this output

Array
(
    [1] => Array
        (
            [42] => John
        )

    [2] => Array
        (
            [32] => Jane
        )

    [3] => Array
        (
            [25] => John
        )
)

which avoids overwriting any duplicate names or scores, but leaves me in a position where I can't (to my knowledge) use arsort() to sort the array in to highest to lowest.


Solution

  • You can use array_multisort for that, in combination with array_column. Because the key values are strings, you need to also convert them to integers, for which you can use array_map("intval", ...):

    foreach($arr as $value) {
      $result[] = explode("|", $value);
    }
    array_multisort(array_map("intval", array_column($result, 0)), $result);
    

    After the above code has run, $result will be sorted by the key values:

    [
        ['25', 'John'],
        ['32', 'Jane'],
        ['42', 'John']
    ]
    

    To reverse the order, apply array_reverse to the result.

    Alternative

    You could also decide to sort the original array without conversion to a 2D array, and sort it with a custom sort callback, using usort and (again) intval:

    usort($arr, function ($a, $b) {
        return intval($a) - intval($b);
    });
    

    Then $arr will be sorted to:

    [
        '25|John',
        '32|Jane',
        '42|John'
    ]
    

    To reverse the order, switch the position of $a and $b in the sort callback function:

        return intval($b) - intval($a);