2

How, from this array, I can filter the duplicate values?

Actually, for the same country and city, the data are the same - Except the population changed.

How can I remove the array that contains the higher population?

$arr = array
(
    "100" => array(
        array(
            "country" => 'France',
            "city" => 'Paris',
            "population" => '1800000',
        ),
        array(
            "country" => 'France',
            "city" => 'Paris',
            "population" => '2000000',
        ),
        array(
            "country" => 'France',
            "city" => 'Toulouse',
            "population" => '500000',
        ),
    )
    "101" => array(
        array(
            "country" => 'Russia',
            "city" => 'Moscow',
            "population" => '144000000',
        )
    )
);

So the desired output should be:

$arr = array
(
    "100" => array(
        array(
            "country" => 'France',
            "city" => 'Paris',
            "population" => '1800000'
        ),
        array(
            "country" => 'France',
            "city" => 'Toulouse',
            "population" => '500000'
        ),
    )
    "101" => array(
        array(
            "country" => 'Russia',
            "city" => 'Moscow',
            "population" => '144000000',
        )
    )
);

This is what I tried:

$temp_array = [];
foreach ($array as &$v) {
    if (!isset($temp_array[$v['country']] && $temp_array[$v['city']]))
        $temp_array[$v[$key]] =& $v;
    }
$array = array_values($temp_array);
return $array;

4 Answers 4

3

You can first use array_reduce for filtering the lower population (use the combination of country and city as key). Then explode them and reset the array with that min value:

foreach($arr as $k => &$ar) {
    $temp = array_reduce($ar, function ($carry, $item) {
        $key = $item["country"] . "###" . $item["city"];
        $carry[$key] = (isset($carry[$key]) && $item["population"] > $carry[$key]) ?  $carry[$key] : $item["population"];
        return $carry;
    }, []);
    $ar = [];
    foreach($temp as $k => $val) {
        list($country, $city) = explode("###", $k);
        $ar[] = array("country" => $country, "city" => $city, "population" => $val);
    }
}

Live example: 3lv4

Edit:

You can use array_filter instead the foreach loop to avoid coping:

$ar = array_filter($ar, function ($item) use ($mins) {
    $key = $item["country"] . "###" . $item["city"];
    return $mins[$key] == $item["population"];
 });
Sign up to request clarification or add additional context in comments.

6 Comments

"city" = "Moscow" is not part of the question
@Andreas it is part of the desire output so assuming OP has typo
Actually, the problem with your solution is the need to copy/paste the value to pass to the new array $ar[] = array("country" => $country, "city" => $city, "population" => $val);. Thanks.
@Testy if the copy bother you use array_filter - edit my post
Hum. Very good. Could you please update the link? Also could you remove the part with the city ?
|
0

from the looks of it the array is already grouped by country, i'm assuming that each array element only has child arrays from the same country. I'd also say it's more sensible to have an array with keys for each country anyway for easier access and filtering down the line so I would say

$populations = [];

foreach($array as $arr) {
if(!isset($populations[$arr['country']])) $populations[$arr['country']] = [];//create an array entry for the country
     $cities = [];
     foreach($arr as $city) {
       if(!isset($cities[$city]) || $cities[$city]['population'] > $city['population']) $cities[$city] = ['population' => $city['population']];//you could put the value straight in, but this means if you expand later you could add extra fields to each cities info such as district, number of unemployed or whatever you're using this for

     }
$populations[$arr['country']] = $cities;
}

this is a slightly different output to that which you have outlined, but i think it will make it simpler to use further on as you can access all data for specific countries, and then for cities therein rather than having to continually loop through and check if the child contains a country you are after.

I hope this makes sense, my fiancee is trying to talk to me about ikea at the same time as I'm answering, so it may not be 100% perfect but will point you in a good direction at least

Comments

0

what I did two nested loops, the first gets the subarray that contains all the content for a specific key (e.g. 100 and 101).

next I iterate through the data, and keep a temporary array with two levels, the first will be the country as key, and the second will be the city as key that tracks the lowest population.

once the above is done, I iterate through the temporary array to get the country, city and population in the correct format and append it to a new array. I then substitute the previous array for this newly acquired result.

<?php

$arr = array
(
    "100" => array(
        array(
            "country" => 'France',
            "city" => 'Paris',
            "population" => '1800000',
        ),
        array(
            "country" => 'France',
            "city" => 'Paris',
            "population" => '2000000',
        ),
        array(
            "country" => 'France',
            "city" => 'Toulouse',
            "population" => '500000',
        ),
    ),
    "101" => array(
        array(
            "country" => 'Russia',
            "city" => 'Moscow',
            "population" => '144000000',
        )
    )
);

foreach($arr as $key=>$subarr) {
    $tmp = array();
    foreach($subarr as $v) {
        $country = $v['country'];
        $city = $v['city'];
        $population = $v['population'];

        if(isset($tmp[$country])) {
            if(isset($tmp[$country][$city])) {
                if($tmp[$country][$city] > $population) {
                    $tmp[$country][$city] = $population;
                }
            } else {
                $tmp[$country][$city] = $population;
            }
        } else {
            $tmp[$country] = array();
            $tmp[$country][$city] = $population;
        }
    }

    $res = array();
        foreach($tmp as $country=>$cities) {
            foreach($cities as $city=>$population) {
                $res[] = array('country'=>$country,'city'=>$city,'population'=>$population);
            }
        }
    $arr[$key] = $res;

}
print_r($arr);

Comments

0

You can make a compound array key with the country and city that way it's easy to keep track of what you have looped.
Since city may not be in the arrays then a if it needed to not get a notice.

foreach($arr as $key => $sub){
    foreach($sub as $item){
        if(isset($item['city'])){
            if(!isset($res[$key][$item['country'] . $item['city']])) $res[$key][$item['country'] . $item['city']] = $item;
            if($res[$key][$item['country'] . $item['city']] < $item['population']) $res[$key][$item['country'] . $item['city']] = $item;
        }else{
            if(!isset($res[$key][$item['country']])) $res[$key][$item['country']] = $item;
            if($res[$key][$item['country']] < $item['population']) $res[$key][$item['country']] = $item;
        }
    }
}
var_dump($res);

Output:

array(2) {
  [100]=>
  array(2) {
    ["FranceParis"]=>
    array(3) {
      ["country"]=>
      string(6) "France"
      ["city"]=>
      string(5) "Paris"
      ["population"]=>
      string(7) "1800000"
    }
    ["FranceToulouse"]=>
    array(3) {
      ["country"]=>
      string(6) "France"
      ["city"]=>
      string(8) "Toulouse"
      ["population"]=>
      string(6) "500000"
    }
  }
  [101]=>
  array(1) {
    ["Russia"]=>
    array(2) {
      ["country"]=>
      string(6) "Russia"
      ["population"]=>
      string(9) "144000000"
    }
  }
}

https://3v4l.org/KNuId

If you need to remove the keys such as "FranceToulouse" then just loop the array again and use array_values

4 Comments

Hello. Thanks for your time. How can I remove after the key like "FranceParis"? Thanks.
I added that to my answer just a few seconds ago. Update the page and it ahould be there
I can't see it sorry. It keeps echoing the "FranceParis".
@Testy I'm flattered that you accepted my answer but I believe dWinders answer is a better answer. It's your decision and you should accept the answer you find best, but I actually think you have not given his answer enough chance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.