【问题标题】:Spliting .txt file lines in to multi-layered array key value pairs then sorting it将 .text 文件行拆分为多层数组键值对,然后将其存储
【发布时间】:2018-05-07 18:30:18
【问题描述】:

由于这个问题有一个很长的解释,我会问这个问题,然后有下面的解释 - 你可以通过内部数组键值对多维数组进行排序,还是有更好的方法来绕过排序键值将不可避免地重复的对,而不仅仅是使用数组?

我对 PHP 的使用基本不熟悉,想学习如何存储数据。

我制作的 非常 简单示例只是两个 HTML 表单输入,用于一个分数和一个名称以及一个 PHP 文件,用于处理要存储在纯 .txt 文件中的输入,该文件最初是编写的与模式

42|John
32|Jane
25|John

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

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

42|John
32|Jane
25|John

将被排序到

32|Jane
25|John

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

目前我的解决方案是为每个名称/分数对设置一个唯一的额外数字,我在文本文件中将其格式化为

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() 将数组从高到低排序的位置。

【问题讨论】:

  • 旁注:您为什么不为此使用数据库有什么特别的原因吗?文件是很多工作。而你现在使用的可能不是很安全。那么,这是出于学术目的还是上线?
  • 两件事:这是一个小型的学习项目,所以我很乐意做额外的工作来解决这个问题,我还没有找到任何关于如何开始使用数据库的帮助有任何意义@Fred-ii-
  • 我曾经在一个项目中使用平面文件数据库,如果我使用的是实际的 (mysql) 数据库,我的生活会变得更轻松。学习(它)是必然的,这是我做过的最好的举动。我花了几个月的时间,但我在 Stack 和网络其他地方发现的许多问答中获得了很多经验。如果你有时间学习它,相信我你会(可能)希望你能早点学会它。我对数据库感到有点害怕,但很快就消失了。我不会骗你的。
  • 据我所知,这些地方是我从mysqltutorial.org --- tutorialspoint.com/mysql --- siteground.com/tutorials/php-mysql/mysql 和 MySQL.com 官方网站 dev.mysql.com/doc/refman/5.7/en 那里学到的 --- 还有还有使用准备好的语句,你真的应该学习en.wikipedia.org/wiki/Prepared_statement,以帮助防止 SQL 注入。 P.s.:我还在学习 ;-) 也通过我的一些答案。
  • 不客气,Zachary,享受学习;我做到了 :-) 干杯,慢慢来,你会到达那里的。

标签: php html arrays forms flat-file


【解决方案1】:

您可以为此使用array_multisort,并结合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 和(再次)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);

【讨论】:

  • 是否可以与 strcmp() 进行相反的操作以将它们按降序排序?使用数组反转功能会更容易吗?
  • 当然,要么在strcmp 前加一个减号,要么在该表达式中将$a$b 交换。
  • 好吧,在快速测试之后,我注意到比较字符串会将值 100|personA,在 23|personB 之前都放在 4|personC 之前,因为它是比较字符串,而不是整数值,有没有办法将第二个答案的简单性与第一个答案的功能结合起来?
  • 我认为目的是按名称排序。你到底想按什么排序?您想丢弃名称,并按第一部分的数值排序吗?还是别的什么?
  • 我已更新我的答案以按行的数字部分排序。让我知道这是否是您想要的。
【解决方案2】:

如果我们像这样对您的 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
        )
)

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

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

到这里:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 2015-02-10
    • 2018-10-06
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多