5

I need to count the same values in multidimensional array and remove duplicates

My array now

[0] => Array
    (
        [id] => 1
        [title] => BMW
    )

[1] => Array
    (
        [id] => 1
        [title] => BMW
    )

[2] => Array
    (
        [id] => 2
        [title] => Mercedes
    )       
.......

Need to output

[0] => Array
    (
        [id] => 1
        [title] => BMW
        [count] => 2
    )

[1] => Array
    (
        [id] => 2
        [title] => Mercedes
        [count] => 1
    )       

I will be very grateful for your help

2
  • is it possible for the the id to be 1 and the title to be Mercedes? or is id 2 always associated with Mercedes? If the only changing factor is the id, this simplifys things. Commented Feb 7, 2015 at 16:52
  • yes, id 2 always associated with Mercedes Commented Feb 7, 2015 at 16:58

4 Answers 4

4

The key problem is that an array(that with an id and a title) is not hashable.

So we can try to hash it, just join them all together, and make the result string as a hash key.

So, we maintain a hash table, which key is the object hash key, and the value is the result array index.

And then, For each item we travel, we can find the result array position by the help of the hash table, and then add the count.

Here's my code.

<?php

$array_in = array(
    array('id'=>1, 'title'=>'BMW'),
    array('id'=>1, 'title'=>'BMW'),
    array('id'=>2, 'title'=>'Mercedes'),
);

$hash = array();
$array_out = array();

foreach($array_in as $item) {
    $hash_key = $item['id'].'|'.$item['title'];
    if(!array_key_exists($hash_key, $hash)) {
        $hash[$hash_key] = sizeof($array_out);
        array_push($array_out, array(
            'id' => $item['id'],
            'title' => $item['title'],
            'count' => 0,
        ));
    }
    $array_out[$hash[$hash_key]]['count'] += 1;
}

var_dump($array_out);
Sign up to request clarification or add additional context in comments.

Comments

2

In this sample I've used array_reduce to build a second array out of appropriate elements from your first array. Due to the way that I check for duplicate values, this assumes that your initial array is sorted (all the dupes are next to each other).

function dedupe($carry, $item) {
    // check if array is non empty, and the last item matches this item
    if (count($carry) > 0 
        && $carry[count($carry) - 1][0] == $item[0] 
        && $carry[count($carry) - 1][1] == $item[1]) {

        // the array contains a match, increment counter
        $carry[count($carry) - 1][2]++;
    } else {
        // there was no match, add element to array
        $carry[] = array($item[0], $item[1], 1);
    }
    return $carry;
}

$cars = array(
    array(1, "BMW"),
    array(1, "BMW"),
    array(2, "Mercedes")
);

$uniques = array_reduce($cars, "dedupe", array());

var_dump($uniques);

Comments

2

You can iterate over the array and construct the final array following this pattern:

If a key with the id of the element exists in the final array, update its counter.

If it doesn't, create a new element with its id as key.

$orig = array(
    array('id' => 1, 'title' => 'BMW'),
    array('id' => 1, 'title' => 'BMW'),
    array('id' => 2, 'title' => 'Mercedes'),
);

$result = array();
foreach ($orig as $element) {
    (isset($result[$element["id"]])) ?
                    $result[$element["id"]]["count"] += 1 :
                    $result[$element["id"]] = array("id" => $element["id"], "title" => $element["title"], "count" => 1);
}
print_r($result);

Comments

2
$cars = array(
    array('id'=>1, 'title'=>'BMW'),
    array('id'=>1, 'title'=>'BMW'),
    array('id'=>2, 'title'=>'Mercedes'),
);

$serialize = array_map("serialize", $cars);
$count     = array_count_values ($serialize);
$unique    = array_unique($serialize);

foreach($unique as &$u)
{
    $u_count = $count[$u];
    $u = unserialize($u);
    $u['count'] = $u_count;
}

print_r($unique);

Else if the count is not necessary you can simply follow this example:

$result = array_map("unserialize", array_unique(array_map("serialize", $array_in)));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.