Remove Duplicate Value from Associative Array

Although array_unique can remove duplicate values from an array, in some situations, the array you need to deal with is quite complex and totally doesn't fit in array_unique. The following array is an associate array with a duplicate value in a nested array:

$arr = [
    [
        'name' => 'a',
        'channels' => [
            ['id' => 1, 'value' => 111],
            ['id' => 2, 'value' => 222],
        ]
    ], [
        'name' => 'b',
        'channels' => [
            ['id' => 3, 'value' => 111], // remove
            ['id' => 4, 'value' => 333],
        ]
    ], [
        'name' => 'c',
        'channels' => [
            ['id' => 5, 'value' => 333], // remove
            ['id' => 6, 'value' => 333], // remove
            ['id' => 7, 'value' => 666],
            ['id' => 8, 'value' => 666], // remove
            ['id' => 9, 'value' => 888],
        ]
    ]
];

The remove rule is to filter out duplicate 'value' in channels, if it appears again, then the whole item should be removed(marked with 'remove' in the above code snippet). The desired output is:

$arr = [
    [
        'name' => 'a',
        'channels' => [
            ['id' => 1, 'value' => 111],
            ['id' => 2, 'value' => 222],
        ]
    ], [
        'name' => 'b',
        'channels' => [
            ['id' => 4, 'value' => 333],
        ]
    ], [
        'name' => 'c',
        'channels' => [
            ['id' => 7, 'value' => 666],
            ['id' => 9, 'value' => 888],
        ]
    ]
];

The trickiest part is that it is difficult to loop an array and remove elements at the same time. The short answer is: don't, don't remove element while loop array. Doing them at the same time could cause many unexpected behaviours. The following is a simple and clear solution:

$unique = [];
foreach ($arr as &$item) {
    $newChannel = [];
    foreach ($item['channels'] as $key => $channelItem) {
        if (in_array($channelItem['value'], $unique)) {
            continue;
        }
        $newChannel []= $channelItem;
        $unique[] = $channelItem['value'];
    }
    $item['channels'] = $newChannel;
}

The best part about the solution is you don't tamper with the channel values while looping, instead, you replace it with filtered array after loop process, it removes many possible error worries.