Удалить массив дубликатов из многомерного массива в PHP

#php #arrays #multidimensional-array #duplicates

#php #массивы #многомерный-массив #дубликаты

Вопрос:

Как из этого массива я могу отфильтровать повторяющиеся значения?

На самом деле, для того же country и city , данные те же — за исключением измененной совокупности.

Как я могу удалить массив, содержащий более высокую совокупность?

 $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',
        )
    )
);
 

Таким образом, желаемый результат должен быть:

 $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',
        )
    )
);
 

Это то, что я пробовал:

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

Ответ №1:

Сначала вы можете использовать array_reduce для фильтрации меньшей совокупности (используйте комбинацию country и city в качестве ключа). Затем разбейте их и сбросьте массив с этим минимальным значением:

 foreach($arr as $k => amp;$ar) {
    $temp = array_reduce($ar, function ($carry, $item) {
        $key = $item["country"] . "###" . $item["city"];
        $carry[$key] = (isset($carry[$key]) amp;amp; $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);
    }
}
 

Живой пример: 3lv4

Редактировать:

Вместо этого вы можете использовать цикл, чтобы избежать дублирования array_filter foreach :

 $ar = array_filter($ar, function ($item) use ($mins) {
    $key = $item["country"] . "###" . $item["city"];
    return $mins[$key] == $item["population"];
 });
 

Комментарии:

1. "city" = "Moscow" не является частью вопроса

2. @Andreas это часть вывода desire, поэтому предполагается, что в OP есть опечатка

3. На самом деле, проблема с вашим решением заключается в необходимости скопировать / вставить значение для передачи в новый массив $ar[] = array("country" => $country, "city" => $city, "population" => $val); . Спасибо.

4. @Testy если копия вас беспокоит array_filter — отредактируйте мой пост

5. Жужжание. Очень хорошо. Не могли бы вы обновить ссылку? Также не могли бы вы удалить часть с city помощью?

Ответ №2:

судя по всему, массив уже сгруппирован по странам, я предполагаю, что каждый элемент массива имеет только дочерние массивы из той же страны. Я бы также сказал, что более разумно иметь массив с ключами для каждой страны в любом случае для облегчения доступа и фильтрации по строке, поэтому я бы сказал

 $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;
}
 

это немного отличается от того, что вы описали, но я думаю, что это упростит дальнейшее использование, поскольку вы можете получить доступ ко всем данным для определенных стран, а затем для городов в них, вместо того, чтобы постоянно перебирать и проверять, содержит ли дочерний элемент страну, которую вы ищете.

Я надеюсь, что это имеет смысл, моя невеста пытается поговорить со мной об ikea одновременно с тем, как я отвечаю, так что это может быть не на 100% идеально, но, по крайней мере, укажет вам хорошее направление

Ответ №3:

то, что я сделал двумя вложенными циклами, первый получает подмассив, содержащий все содержимое для определенного ключа (например, 100 и 101).

затем я перебираю данные и сохраняю временный массив с двумя уровнями, первым будет страна в качестве ключа, а вторым будет город в качестве ключа, который отслеживает наименьшее население.

как только это будет сделано, я выполняю итерацию по временному массиву, чтобы получить страну, город и население в правильном формате и добавить их в новый массив. Затем я заменяю предыдущий массив на этот вновь полученный результат.

 <?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);
 

Ответ №4:

Вы можете создать составной ключ массива со страной и городом, чтобы было легко отслеживать, что вы зациклили.
Поскольку город может отсутствовать в массивах, тогда a, если ему нужно, чтобы не получать уведомление.

 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);
 

Вывод:

 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

Если вам нужно удалить ключи, такие как «FranceToulouse», просто повторите цикл массива и используйте array_values

Комментарии:

1. Здравствуйте. Спасибо за ваше время. Как я могу удалить после ключа like "FranceParis" ? Спасибо.

2. Я добавил это к своему ответу всего несколько секунд назад. Обновите страницу, и она должна быть там

3. Извините, я этого не вижу. Он продолжает повторять "FranceParis" .

4. @Testy Я польщен тем, что вы приняли мой ответ, но я считаю, что ответ Истощения — лучший ответ. Это ваше решение, и вы должны принять ответ, который вы считаете лучшим, но я действительно думаю, что вы не дали его ответу достаточно шансов.