具有合并和排序的多维数组的字符串

时间:2015-10-15 12:27:05

标签: php sorting multidimensional-array

在多次使用CONCAT()后,我有这种来自我的数据库的字符串。

1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10

为了清楚地说明一点,让我们这样说:

  • 大字符串由多个子字符串组成,全部以;
  • 结尾
  • 每个子字符串由四个元素组成:
    • 第一个号码。我们称之为Group
    • 一封信或一组信件。它们被称为Section
    • 第二个号码。我们将其称为From
    • 第三个也是最后一个数字。我们将其称为To

使用此代码

$data = "1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10";
echo $data;
    $ret = array_map (
    function ($_) {return explode (', ', $_);},
        explode (';', $data)
    );

我得到以下多维数组

Array
(
    [0] => Array
        (
            [0] => 1 
            [1] => AA 
            [2] => 6 
            [3] => 10 
        )

    [1] => Array 
        ( 
            [0] => 1 
            [1] => Z 
            [2] => 1 
            [3] => 5 
        ) 

    [2] => Array 
        ( 
            [0] => 2 
            [1] => AE 
            [2] => 1 
            [3] => 5 
        ) 

    [3] => Array 
        ( 
            [0] => 2 
            [1] => AF 
            [2] => 6 
            [3] => 10 
        ) 

    [4] => Array 
        ( 
            [0] => 3 
            [1] => X 
            [2] => 1 
            [3] => 5 
        ) 

    [5] => Array 
        ( 
            [0] => 3 
            [1] => Y 
            [2] => 5 
            [3] => 10 
        ) 

)

我希望以一个看起来像这样的多维数组结束:

Array
(
    [0] => Array
        (
            [0] => 1 
            [1] => Array
                (                   
                    [0] => Z
                    [1] => 1 
                    [2] => 5 
                )
            [2] => Array
                (                   
                    [0] => AA 
                    [1] => 6
                    [2] => 10
                )
        )

    [1] => Array 
        ( 
            [0] => 2 
            [1] => Array
                (
                    [1] => AE 
                    [2] => 1 
                    [3] => 5 
                )
            [2] => Array
                (
                    [1] => AF 
                    [2] => 6 
                    [3] => 10
                )
        ) 

    [2] => Array 
        ( 
            [0] => 3 
            [1] => Array
                (
                    [1] => X 
                    [2] => 1 
                    [3] => 5 
                )
            [2] => Array
                (
                    [1] => Y 
                    [2] => 6 
                    [3] => 10
                )
        )
) 

我不知道最好的方法是什么才能获得这个结果,也不知道如果没有太复杂的操作就可以做到这一点。 获得最终结果的最佳方法是什么?我应该处理“原始”多维数组还是应该从一开始就使用字符串?

合并具有相同Group

的数组

首先,我想合并以相同Group值开头的子字符串。然后每个字符串的其余部分成为新创建的数组中的另一个数组。 我想我可以通过解析初始数组(或者字符串本身?)并将结果推送到新数组,同时合并数据来实现。 在我的例子中,它已经完成了六个起始数组,现在分成三个数组。

使用FromTo值进行排序

将具有相同Group值的子字符串组合成数组后,我想对这些数组进行排序,以使子数组的To值始终小于From值下一个。 始终使用以下规则生成初始字符串:

  • 永远不会有FromTo重叠的值:1,5 - 4,7。它可以是1,4 - 5,71,5 - 6,7
  • 序列中永远不会缺少数字,因此您永远不会有1,3 - 5,7
  • 之类的内容
  • 同一数组的FromTo值可以相同。所以你可以得到:1,4 - 5,5 - 6,7

这就是为什么1, AA, 6, 10; 1, Z, 1, 5;已排在Z, 1, 5之后AA, 6, 10。是否有可以进行这种排序的PHP函数(通过比较不同键的值)或者我应该自己创建吗?

另外,如果您认为我应该完全改变我想要这样做的方式(使用多维数组......)并且您有一些想法,请继续并分享它们。我也在这里学习新的做事方式。

有关数据库结构的版本

如@deceze所述,在SQL查询期间构造初始字符串可能更容易。我试过了,但我可能不够熟练,无法得到我想要的东西。我的数据库看起来像这样: Database Structure 如您所见,所有行都由MasterID链接。这是因为我在多个表上进行1到n查询。 到目前为止,我的查询看起来像那样(我从中删除了所有不必要的东西):

SELECT s.MasterID,
    GROUP_CONCAT(CONCAT( CONCAT( CONCAT( CONCAT( CONCAT(
        s2d.Group, ', '),
        s2d.Section, ', '),
        s2d.From),', '),
        s2d.To) SEPARATOR '; ') AS Concatstuff,
    FROM table1 AS s
    JOIN table2 AS s2d
        ON s2d.MasterID = s.MasterID
    WHERE MasterID = $MasterID (A PHP variable)

由于1到N的关系,我不知道如何以不同的方式做到这一点。也许我可以保持简单并执行两个查询而不是一个。在第一个查询中,我从table1获取信息,在第二个查询中获取table2中的信息。 但是如果你知道一种方法只在一个查询中完成所有这些,我很想知道如何做到这一点!

2 个答案:

答案 0 :(得分:2)

我建议在进行许多PHP更改之前修改MySQL查询。

大量的会话将会变得非常大,最终你甚至可能需要调整GROUP_CONCAT()的MySQL配置设置,因为它会在一定长度后截断。

相反,我们可以将GROUP_CONCAT()和群组专门保留在具有GROUP BY的各个masterid / group组合上。此外,GROUP_CONCAT()具有ORDER BY属性,可解决排序问题:

SELECT
    s.MasterID,
    s2d.`group`,
    GROUP_CONCAT(
        s2d.`section`, ',', s2d.`from`, ',', s2d.`to`
        ORDER BY `from`, `to`
        SEPARATOR ';'
    ) AS Concatstuff
FROM
    table1 AS s
    JOIN table2 AS s2d
        ON s2d.MasterID = s.MasterID
GROUP BY
    s.MasterID, s2d.`group`
WHERE
    s.MasterID = $MasterID;

这应该给我们类似的数据:

MasterID    group   Concatstuff
2           1       z,1,5;aa,6,10
2           2       ae,1,5;af,6,10
2           3       x,1,5;y,6,10

假设您已从数据库中检索到此内容并将其存储在名为$results的数组中,我们可以迭代它:

$final_groups = array();
foreach ($results as $group) {
    // your original `array_map()` logic:
    $split_group = array_map(function($_) {
            return explode(',', $_);
        },
        explode(';', $group['Concatstuff'])
    );

    // ... any other processing you want to do

    // store the results:
    $final_groups[$group['group']] = $split_group;
}

注意:明确回答您的问题

  

是否有可以进行此类排序的PHP函数

是的,usort()

function sort_group($a, $b) {
    // [1] = 'from'
    // [2] = 'to'

    if ($a[1] == $b[1]) {
        if ($a[2] == $b[2]) {
            return 0;
        }
        return ($a[2] < $b[2]) ? -1 : 1;
    }

    return ($a[1] < $b[1]) ? -1 : 1;
}

usort($split_group, 'sort_group');

您可以在sort_group()中自定义比较逻辑,以匹配您想要的任何内容。上面,我按 fromto =]

进行排序

答案 1 :(得分:0)

尝试在不为您编写代码的情况下给出一般答案:

  • 对于每个组,您可以使用组号作为所包含数据的索引。

  • 对于每个组,您将其组索引写入具有索引字符串前缀加数字零的元素:$ret1[$group_number]['d0'] = $group_number;。每次向群组添加内容时都会被覆盖。

  • 然后使用适合排序的字符串索引添加组内容。我建议使用sprintf()生成索引,如$idx = sprintf('d%05.1f%05.1f', $from, $to);,因此组编号将始终排在前面。再次这里是前缀。添加$ret1[$group_number][$idx] = $group_array;

为所有输入数据完成此操作后,运行它以进行排序和完成:

  • $ret1中的所有群组进行迭代,按键对其进行排序,然后使用array_values()删除密钥。使用$ret[] = ...将其添加到新阵列。