PHP嵌套数组' Mesh Like'分组

时间:2016-08-13 01:15:51

标签: php arrays grouping

我在PHP中为这个问题编写准确有效的代码时会遇到一些问题。

我有一个用户列表,每个用户都有一个好友列表。我想将所有朋友分组,每个人至少有一个朋友和另一个用户。

下面是一个简化的数组,删除了不需要的数组键,并将用户ID替换为名称。

Array

    [Ted] => Array
        [friends] => Array
                    [0] => Sarah

    [John] => Array
            [friends] => Array
                    [0] => Peter
                    [1] => Sam

    [Peter] => Array
            [friends] => Array
                    [0] => John
                    [1] => Sam

    [Frank] => Array
            [friends] => Array
                    [0] => Bob
                    [1] => Sarah

    [Kevin] => Array
            [friends] => Array
                    [0] => Sally

    [Sam] => Array
            [friends] => Array
                    [0] => John
                    [1] => Peter

    [Bob] => Array
            [friends] => Array
                    [0] => Frank
                    [1] => Sarah

    [Sarah] => Array
            [friends] => Array
                    [0] => Frank
                    [1] => Bob
                    [2] => Ted
                    [3] => Jane

    [Sally] => Array
            [friends] => Array
                    [0] => Kevin

    [Jane] => Array
            [friends] => Array

此输出应如下:

第1组: Sarah,Frank,Bob,Jane,Ted

第2组: John,Peter,Sam

第3组:莎莉,凯文

作为一个说明,Jane没有数据,但Sarah是她的朋友,所以这种分组可能会发生。也会有没有朋友的用户,他们应该被安排在自己的小组中。

我曾尝试为此编写代码,但效率非常低,并且包含三个嵌套的foreach循环。 我很惭愧:(

$friendGroups = [];


foreach($userdata as $key => $user)
{
    $friends = $user["friends"];

    // Loop the current groups
    foreach($friendGroups as $friendkey => $friendValue)
    {
        // Does the group contain any of the friends?
        foreach($friends as $friendID)
        {
            if (array_key_exists($friendID, $friendValue))
            {
                // add the friends to this group
                foreach($friends as $friendIDx)
                {
                    $friendGroups[$friendkey][$friendIDx] = $userdata[$friendIDx];
                }
                continue 3;
            }
        }
    }

    $groupID = count($friendGroups);
    // Create a new group
    foreach($friends as $friendID)
    {
        $friendGroups[$groupID][$friendID] = $userdata[$friendID];
    }
}

1 个答案:

答案 0 :(得分:1)

一个非常简单且可能不是最佳的解决方案是将输入数组首先展平为一维数组的数组。您只需要知道哪些初始组有匹配的朋友,这样您就可以知道哪些组要相互合并。

展平您的示例输入数组将导致:

Array
(
    [0] => Array
        (
            [0] => Ted
            [1] => Sarah
        )

    [1] => Array
        (
            [0] => John
            [1] => Peter
            [2] => Sam
        )

    [2] => Array
        (
            [0] => Peter
            [1] => John
            [2] => Sam
        )

    [3] => Array
        (
            [0] => Frank
            [1] => Bob
            [2] => Sarah
        )

    [4] => Array
        (
            [0] => Kevin
            [1] => Sally
        )

    [5] => Array
        (
            [0] => Sam
            [1] => John
            [2] => Peter
        )

    [6] => Array
        (
            [0] => Bob
            [1] => Frank
            [2] => Sarah
        )

    [7] => Array
        (
            [0] => Sarah
            [1] => Frank
            [2] => Bob
            [3] => Ted
            [4] => Jane
        )

    [8] => Array
        (
            [0] => Sally
            [1] => Kevin
        )

    [9] => Array
        (
            [0] => Jane
        )

)

您可以使用array_intersect检查每个组的匹配好友以及array_unique和array_merge的组合以合并两个组。

以下是此方法的一个示例:

function flatten($input) {
    $output = [];

    $i = 0;
    foreach ($input as $name => $data) {
        $output[$i] = [$name];
        foreach ($data['friends'] as $friend) {
            $output[$i][] = $friend;
        }

        $i++;
    }

    return $output;
}

$input = [
    'Ted' => [
        'friends' => [
            'Sarah'
        ]
    ],

    'John' => [
        'friends' => [
            'Peter',
            'Sam'
        ]
    ],

    'Peter' => [
        'friends' => [
            'John',
            'Sam'
        ]
    ],

    'Frank' => [
        'friends' => [
            'Bob',
            'Sarah'
        ]
    ],

    'Kevin' => [
        'friends' => [
            'Sally'
        ]
    ],

    'Sam' => [
        'friends' => [
            'John',
            'Peter'
        ]
    ],

    'Bob' => [
        'friends' => [
            'Frank',
            'Sarah'
        ]
    ],

    'Sarah' => [
        'friends' => [
            'Frank',
            'Bob',
            'Ted',
            'Jane'
        ]
    ],

    'Sally' => [
        'friends' => [
            'Kevin'
        ]
    ],

    'Jane' => [
        'friends' => []
    ]
];

$flattened = flatten($input);

for ($i = 0; $i < count($flattened); $i++) {
    $mergedIndices = [];
    // Check for same friends among other groups than current one
    for ($j = 0; $j < count($flattened); $j++) {
        if ($i !== $j && count(array_intersect($flattened[$i], $flattened[$j])) > 0) {
            // Found match between two groups, so merge them
            $flattened[$i] = array_unique(array_merge($flattened[$i], $flattened[$j]));
            $mergedIndices[] = $j;
        }
    }

    // Purge merged items
    foreach ($mergedIndices as $m) {
        unset($flattened[$m]);
    }

    // Re-index array after purging
    $flattened = array_values($flattened);
}

echo '<pre>' . print_r($flattened, 1) . '</pre>';

这是示例数据的输出:

Array
(
    [0] => Array
        (
            [0] => Ted
            [1] => Sarah
            [2] => Frank
            [3] => Bob
            [4] => Jane
        )

    [1] => Array
        (
            [0] => John
            [1] => Peter
            [2] => Sam
        )

    [2] => Array
        (
            [0] => Kevin
            [1] => Sally
        )

)