Merging data of common keys in a same array - php

so I have an array like this :-
$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
I need it like :-
array("country" => "Netherlands", "city" => "Amsterdam,Tillsburg");
array("country" => "Sweden", "city" => "Stockholm");
How do I merge the values?
Here's what I have tried till now, but it doesn't seems to be working.
function merge($headers) {
$final = [];
foreach($headers as $current) {
if(!in_array($current['country'], $final)) {
$final[] = $current['country'];
}
}
foreach($headers as $current) {
$final[$current['country']]['city'] = $current['city'];
}
return $final;
}
Any help would be appreciated.

Use country values as temporary associative keys to determine if concatenation is necessary.
Code: (Demo)
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
foreach ($headers as $row) {
if (!isset($result[$row['country']])) {
$result[$row['country']] = $row; // store the whole row
} else {
$result[$row['country']]['city'] .= ",{$row['city']}"; // concatenate
}
}
var_export(array_values($result)); // reindex the output array
Output:
array (
0 =>
array (
'country' => 'Netherlands',
'city' => 'Amsterdam,Tillsburg',
),
1 =>
array (
'country' => 'Sweden',
'city' => 'Stockholm',
),
)

Maybe this is not the best solution, but I test it, it works.
function merge($headers) {
$final = array();
foreach ($headers as $current) {
if( !isset( $final[ $current['country'] ] ) ) {
$final[$current['country']] = [
'country' => $current['country'],
'city' => $current['city']
];
continue;
}
$final[ $current['country'] ]['city'] = $final[ $current['country'] ]['city'] . ', ' . $current['city'];
}
return $final;
}
Output
array(2) { ["Netherlands"]=> array(2) { ["country"]=> string(11) "Netherlands" ["city"]=> string(20) "Amsterdam, Tillsburg" } ["Sweden"]=> array(2) { ["country"]=> string(6) "Sweden" ["city"]=> string(9) "Stockholm" } }
You can clear keys of result array if you want adding
$final = array_values($final);
before return statement
Demo

$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
$result = array();
foreach($headers as $key => $value) {
$result[$value['country']][] = $value['city'];
}
$finalArray = array();
foreach($result as $k => $v) {
$finalArray[] = array('country' => $k, 'city' => join(',', $v));
}

Create another array with country name as key
<?php
$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
$countries = array_unique(array_column($headers,"country"));
$newHeaders = array();
foreach($headers as $header){
$newHeaders[$header["country"]]["city"][] = $header["city"];
}
print_r($newHeaders);
foreach($newHeaders as $key=>$headers){
echo $key." City : ".implode(",",$headers['city'])."\n";
}
?>
Live Demo Link
Output would be like
Netherlands City : Amsterdam,Tillsburg
Sweden City : Stockholm

Related

Remove duplicates array from a multidimensional array in PHP

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;
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"];
});
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
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);
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

Turn string to nested array php

I am trying to turn a string into a nested array
Here is my string:
a/b/d.docx
and I wanted to be like this:
array(
"name" => "a",
"type" => "folder",
"sub" => array(
"name" => "b",
"type" => "folder",
"sub" => array(
"name" => "c.docx",
"type" => "file",
"size" => "20"
)
)
)
This is the code that I have so far
$items = explode('/', $strings);
$num = count($items);
$num = --$num;
$temp = array();
foreach($items as $keys => $value) {
$temp[$keys] = array(
"name" => $value,
"type" => "folder",
"items" => $temp[++$keys]
);
if($keys == $num){
$temp[$keys] = array(
"name" => $value,
"type" => "file",
"size" => "20"
);
}
}
var_dump($temp);
I am trying this functions but this only turn string into a single array and it also can't do the 'items' line.
Any help would be appreciated.Thanks.
Note that the path is virtual and doesn't exist.
UPDATE: How can I add path to each array??for example,"path"=>"a/b"
You can do that:
$path = 'a/b/d.docx';
$parts = explode('/', $path);
$result = [ 'name' => array_pop($parts), 'type' => 'file', 'size' => 20 ];
while ($parts) {
$result = [ 'name' => array_pop($parts), 'type' => 'folder', 'sub' => $result ];
}
print_r($result);
<?php
$strings='a/b/d.docx';
$items = explode('/', $strings);
$num = count($items)-1;
$root= array();
$cur = &$root;
$v='';
foreach($items as $keys => $value) {
$v = $v.$value;
$temp = array( "name" => $value, "path"=>$v, "type" => "folder", "items" => "");
if($keys == $num){
$temp = array( "name" => $value, "path"=>$v, "type" => "file", "size" => "20");
}
$v= $v.'/';
if($keys==0) {
$cur = $temp;
}
else
{
$cur['items'] = $temp;
$cur = &$cur['items'];
}
}
var_dump($root);
Try recursion:
public function testAction(){
$sString = 'a/b/c/d.exe';
$aExploded = explode('/', $sString);
var_dump($this->_parse_folder_rec($aExploded));
}
private function _parse_folder_rec($aExploded){
$aResult = [];
$aResult['name'] = array_shift($aExploded);
if($aExploded){
$aResult['type'] = 'folder';
$aResult['sub'] = $this->_parse_folder_rec($aExploded);
}else{
$aResult['type'] = 'file';
$aResult['size'] = 20;
}
return $aResult;
}

How to reformatted array

I have an array with indexes like
$array = array(
"first_name" => "test",
"last_name" => "testsurename"
);
I need to convert it to:
$array = array(
"0" => array("first_name" => "test"),
"1" => array("last_name" => "testsurename")
);
try this,
$array = array("first_name"=>"test","last_name"=>"testsurename");
$newarray = array();
foreach($array as $key=> $val)
{
$newarray[][$key] = $val;
}
print_r($newarray);
OUTPUT :
$array = array(
"0" => array("first_name" => "test"),
"1" => array("last_name" => "testsurename")
);
DEMO
Another way is to use array_walk, but basically it's all the same.
$array = array("first_name"=>"test","last_name"=>"testsurename");
$result = array();
array_walk($array,
function(&$item, $key, $target) { $target[] = array($key => $item); },
&$result);
You can try
<?php
$array = array("first_name"=>"test","last_name"=>"testsurename");
$final_array = [];
foreach ($array as $key => $value) {
array_push($final_array, [$key => $value]);
}
print_r($final_array);
Output
Array ( [0] => Array ( [first_name] => test ) [1] => Array ( [last_name] => testsurename ) )
$inputArray = [
"first_name" => "test",
"last_name" => "testsurename"
];
$outputArray = array_reduce(array_keys($inputArray), function($carry, $key) use ($inputArray) {
$carry[][$key] = $array[$key];
return $carry;
}, []);
/**
result will be for $outputArray
[
["first_name" => "test"],
["last_name" => "testsurename"]
];
**/

If value between array key

Example i have this array:
$ar = array(
"1.00" => array("value0"," very bad"),
"1.49" => array("value1","bad"),
"2.00" => array("value2","not bad"),
"2.49" => array("value3","normal"),
"3.00" => array("value4","good"),
"3.49" => array("value5","very good")
);
I want to check if $val is under 1.00 the $result is array("value0"," very bad"). if between range 1.00 - 1,49 the result is array("value1","bad"), etc.
Anyone can help me?
Here is a hint :
<?php
$ar = array(
"1.00" => array("value0"," very bad"),
"1.49" => array("value1","bad"),
"2.00" => array("value2","not bad"),
"2.49" => array("value3","normal"),
"3.00" => array("value4","good"),
"3.49" => array("value5","very good")
);
$input = 1.2;
foreach($ar as $key=>$text)
{
if($input < floatval($key))
{
echo $text[0].' => '.$text[1];
break;
}
}
?>
$val = '2.15';
$val_data = ['value2','not bad'];
$data = array(
"1.00" => array("value0"," very bad"),
"1.49" => array("value1","bad"),
"2.00" => array("value2","not bad"),
"2.49" => array("value3","normal"),
"3.00" => array("value4","good"),
"3.49" => array("value5","very good")
);
$_fkey = array_keys($data)[0];
foreach($data as $key => $value){
if($key > $_fkey && $key < $val){$_fkey = $key;}
}
echo "$val, $val_data\n";
echo "=> $f_key, " . $data[$f_key] . "\n";

Adding another dimension to array

I have an array of TLDs and prices, and now I want to be able to add a classification i.e. 'Australian','New Zealand','Industry' to the domains but I am having troubles adding the extra dimension.
The array I have is
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$domains = array(
'.com.au' => array(
'country' => 'Australia',
'sector' => 'Industry',
'price' => '19.98'
),
);
Is this a beginning on what you're looking for ?
Is this code ok for you?
<?php
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$newDomains = [];
foreach($domains as $key=>$value){
if($key == '.com.au'){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = 'blabal';
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
?>
Or even:
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$industryArray = array(
'.com.au' => 'blabla'
);
$newDomains = [];
foreach($domains as $key=>$value){
if(isset($industryArray[$key])){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = $industryArray[$key];
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
The result is:
array(5) {
[".com.au"]=>
array(2) {
["TLD"]=>
string(5) "19.98"
["Industry"]=>
string(6) "blabla"
}
[".melbourne"]=>
string(5) "90.00"
[".academy"]=>
string(5) "45.00"
[".accountants"]=>
string(6) "120.00"
[".ac.nz"]=>
string(5) "36.75"
}

Categories