将 .text 文件行拆分为多层数组键值对,然后将其存储

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

由于这个问题有很长的解释,我会问这个问题,然后在下面给出解释 -- 你能按内部数组键值对多维数组进行排序吗,或者有没有更好的方法来绕过排序难免有重复的键值对,而不是仅仅使用数组?

我主要不熟悉使用 PHP 并且想学习如何存储数据。

我做的 非常 简单示例只是两个 HTML 表单输入,用于分数和名称,以及一个 PHP 文件来处理输入存储在一个普通的 .txt 文件中,该文件最初是用模式

编写的
42|John
32|Jane
25|John

我能够成功地拆分数据,对其进行排序,添加新的输入值,然后将其全部存储回文本文件中以在其他地方显示,使用名称作为键,分数作为值。

我做这一切只是为了意识到它只会存储排序并显示与每个名称关联的最后一个值(即)

42|John
32|Jane
25|John

将被排序为

32|Jane
25|John

因为你显然不能在一个数组中有两个相同的键,这是我完全忽略的。

我的解决方案,目前是每个 name/score 对都有一个唯一的额外数字,我在文本文件中将其格式化为

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

然后我使用这个 foreach 循环将它们拆分成一个多维数组

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

得到这个输出

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

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

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

这避免了覆盖任何重复的名称或分数,但让我处于无法(据我所知)使用 arsort() 将数组从高到低排序的位置。

如果我们像这样对您的 foreach 迭代进行小的更改:

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

你的数组将有:

Array
(
    [0] => Array
        (
            [score] => 42
            [name] => John
        )

    [1] => Array
        (
            [score] => 32
            [name] => Jane
        )

    [2] => Array
        (
            [score] => 25
            [name] => John
        )
)

您可以使用 uasort 函数,该函数使用数组进行排序,并使用用户定义的函数进行排序。代码如下所示:

function compare($a, $b)
{
    if ($b['score'] == $a['score']) {
        if ($a['name'] == $b['name']) {
            return 0;
        } elseif ($a['name'] < $b['name']) {
            return -1;
        } else {
            return 1;
        }
    } else {
        return ($b['score'] - $a['score']);
    }
}

print_r($scores);
uasort($scores, 'compare');
print_r($scores);

结果如下:

Array
(
    [1] => Array
        (
            [score] => 32
            [name] => Jane
        )

    [2] => Array
        (
            [score] => 25
            [name] => John
        )

    [0] => Array
        (
            [score] => 42
            [name] => John
        )
)

当您使用用户定义的函数进行排序时,您需要 return 3 个值之一(0 个值相等,-1 如果 $a < $b,1 如果 $b > $a。在这种情况下,我们首先按分数(降序)排序,然后按名称(升序)排序。由于您需要从最高分到最低分排序,比较结果是 $b$a ,升序是 $a$b。我认为不需要额外的数字。如果需要,请更改此行:

$scores[] = array('score' => $lineData[1], 'name' => $lineData[2]);

为此:

$scores[$lineData[0]] = array('score' => $lineData[1], 'name' => $lineData[2]);

您可以使用 array_multisort for that, in combination with array_column。因为键值是字符串,你还需要将它们转换为整数,为此你可以使用 array_map("intval", ...):

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

上面代码有运行后,$result会按键值排序:

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

要反转顺序,请对结果应用 array_reverse

备选

您还可以决定在不转换为二维数组的情况下对原始数组进行排序,然后使用自定义排序回调对其进行排序,使用 usort and (again) intval:

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

那么$arr将排序为:

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

要倒序,在排序回调函数中调换$a$b的位置:

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