I have that single array and I need to convert in a multidimensional array without using array_merge, array_replace_recurcive etc, just an autonomous function:
$single = [
0 => 'one',
1 => 'two',
2 => 'tree',
3 => 'four',
4 => 'five'
];
And convert to look like this, with the last key as value:
$multidimentional = [
'one' => [
'two' => [
'tree' => [
'four' => 'five'
]
]
]
];
I have create a recursion function if this helps:
function array_replace_recursive($defaults, $replaces) {
if(is_null($replaces)) {
$replaces = [];
}
if(!is_array($defaults) || !is_array($replaces)) {
return $replaces;
}
foreach($defaults as $key => $value) {
if(!array_key_exists($key, $replaces) || is_null($replaces[$key])) {
$replaces[$key] = $value;
} else {
if(is_array($replaces[$key]) && is_array($value)) {
$replaces[$key] = array_replace_recursive($replaces[$key], $value);
}
}
}
return $replaces;
}
You can do this with PHP (as of 5.6) argument unpacking and a very simple recursive function:
$single = [
0 => 'one',
1 => 'two',
2 => 'tree',
3 => 'four',
4 => 'five'
];
function convert($key, ...$values) {
if (count($values) == 1)
return array($key => $values[0]);
else
return array($key => convert(...$values));
}
print_r(convert(...$single));
Output:
Array
(
[one] => Array
(
[two] => Array
(
[tree] => Array
(
[four] => five
)
)
)
)
You can also do it without using count (only isset):
function convert2($key, ...$values) {
if (!isset($values[1]))
return array($key => $values[0]);
else
return array($key => convert(...$values));
}
print_r(convert2(...$single));
Output:
Array
(
[one] => Array
(
[two] => Array
(
[tree] => Array
(
[four] => five
)
)
)
)
Thinking in recursion, you can write a base case that returns the value of the currently seen item if it is one less than the length of the array.
$singleDim = [
0 => 'one',
1 => 'two',
2 => 'tree',
3 => 'four',
4 => 'five'
];
function toMultiDimArray($arr, $seen=0) {
if ([] === $arr) {
return [];
}
if(count($arr) - 1 === $seen) {
return $arr[$seen];
}
return [
$arr[$seen] => toMultiDimArray($arr, $seen+1)
];
}
$multiDim = toMultiDimArray($singleDim);
var_dump($multiDim);
array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["tree"]=>
array(1) {
["four"]=>
string(4) "five"
}
}
}
}
$single = [
0 => 'one',
1 => 'two',
2 => 'tree',
3 => 'four',
4 => 'five'
];
function to_multidimentional($array, $count = 0, $seen = 0) {
if($count - 1 === $seen) {
return $array[$seen];
}
return [
$array[$seen] => to_multidimentional($array, $count, $seen + 1)
];
}
$single = to_multidimentional($single, count($single));
print_r($single);
exit;
There's nothing recursive about this. It's just iterating over the $single array backwards and then embedding the result inside the new key each time:
function foo( $single ) {
$multidimensional = [ $single[ count($single) - 1 ] ];
for( $i = count($single) - 2; $i >= 0; $i-- ) {
$multidimensional = [ $single[$i] => $multidimensional ];
}
}
Related
I've an array on php that will return a lot of keys->values, like this:
Array
[0] => Array
(
[value] => 405
[information] => some information1
)
[1] => Array
(
[value] => 500
[information] => some information2
)
[2] => Array
(
[value] => 700
[information] => some information3
)
the values are numbers, i need to collect all the values, check the first one that will be >= $determinedvalue and then return the value "information" for this exactly array, is this even possible? I know i can do this if i create a temp table on my database, but i dont want to.
To be more clearly, when my value is "430" it will return me "some information2".
I've searched a lot on google but by now i dont know if this is even possible.
Appreciate any help.
This is a sample on how to do that. Comments in code can be used to explain the execution.
// Sample Array
$arr = array(
array
(
"value" => 405,
"information" => "some information1"
),
array
(
"value" => 500,
"information" => "some information2"
),
array
(
"value" => 700,
"information" => "some information3"
)
);
// Sample Number
$numberToCheck = 430;
// Sub Array To Assign
$subArray = array();
// Loop Through Outer Array
for ( $i = 0; $i < sizeof($arr); $i++)
{
// If Value In Array > Number Check
if ( $arr[$i]['value'] >= $numberToCheck )
{
$subArray = $arr[$i]; // Assign Sub Array
$i = sizeof($arr); // This is Used to Exit For Loop
}
}
print_r($subArray); // Print
Working runnable code: https://tech.io/snippet/QJ93AwV
Code snippent with comments:
<?php
/**
* Helper class for stable sort alogithms
* #see https://github.com/vanderlee/PHP-stable-sort-functions
* Class StableSort
*/
class StableSort
{
static public function usort(array &$array, $value_compare_func)
{
$index = 0;
foreach ($array as &$item) {
$item = array($index++, $item);
}
$result = usort($array, function ($a, $b) use ($value_compare_func) {
$result = call_user_func($value_compare_func, $a[1], $b[1]);
return $result == 0 ? $a[0] - $b[0] : $result;
});
foreach ($array as &$item) {
$item = $item[1];
}
return $result;
}
}
$array = [
// added for test sorting
[
'value' => 9999,
'information' => 'some information-1',
],
[
'value' => 1200,
'information' => 'some information0',
],
// \added for test sorting
[
'value' => 405,
'information' => 'some information1',
],
// added for test sorting stability
[
'value' => 405,
'information' => 'some information1.2',
],
[
'value' => 405,
'information' => 'some information1.1',
],
// \added for test sorting stability
[
'value' => 500,
'information' => 'some information2',
],
[
'value' => 700,
'information' => 'some information3',
],
];
// sort array
$determinedvalue = 430;
StableSort::usort($array, function ($item1, $item2) {
if ($item1['value'] == $item2['value']) return 0;
return $item1['value'] < $item2['value'] ? -1 : 1;
});
// then select the first element by condition
$res = null;
foreach($array as $v) {
if($v['value'] >= $determinedvalue) {
$res = $v['information'];
break;
}
}
// for testing
print $res;
$number = 430;
$array = Array
[0] => Array
(
[value] => 405
[information] => some information1
)
[1] => Array
(
[value] => 500
[information] => some information2
)
[2] => Array
(
[value] => 700
[information] => some information3
)
$firstArray = $array[0];
$secondArray = $array[1];
$threeArray = $array[2];
function selectValueFromArrayRange ($number, $start, $end, $value, $infomation)
{
$startValue = $start[$value];
$endValue = $end[$value];
if ( in_array($number, range($startValue, $endValue)) ) {
return $end[$infomation];
}
}
selectValueFromArrayRange($number, $firstArray, $secondValue, 'value', 'infomation')
I have an array named hello as follows,
hello(
0 => ([name => abc, add=>def, city=>ny,phone=>12345]);
1 => ([name => pqr, add=>mno, city=>qw,phone=>67890]);
2 => ([name => abc, add=>def, city=>ny,phone=>14785]);
3 => ([name => ghi, add=>foo, city=>yu,phone=>258]);
4 => ([name => jkl, add=>exy, city=>ny,phone=>95145]);
);
It has few elements and that elements are also array itself, like while retring query result.
I want to count a perticular name that repeats. Like in hello[0] and hello[2], so my ans should be abc=2.
How can I do that?
Thanks.
Edit 2:
Now you want a way to count all of the objects:
$arr = [
0 => (object) ['name' => 'abc', 'add'=>'def', 'city'=>'ny', 'phone'=>'12345'],
1 => (object) ['name' => 'pqr', 'add'=>'mno', 'city'=>'qw', 'phone'=>'67890'],
2 => (object) ['name' => 'abc', 'add'=>'def', 'city'=>'ny', 'phone'=>'14785'],
3 => (object) ['name' => 'ghi', 'add'=>'foo', 'city'=>'yu', 'phone'=>'258'],
4 => (object) ['name' => 'jkl', 'add'=>'exy', 'city'=>'ny', 'phone'=>'95145'],
];
function countBy (callable $f, $xs) {
return array_reduce($xs, function ($acc, $x) use ($f) {
$y = call_user_func($f, $x);
$acc[$y] = isset($acc[$y]) ? $acc[$y] + 1 : 1;
return $acc;
}, []);
}
json_encode(countBy (function ($x) { return $x->name; }, $arr));
// => { "abc": 2, "pqr": 1, "ghi": 1, "jkl": 1 }
Edit:
You lied about the data types so I changed $x['name'] to $x->name and $x[$attr] to $x->{$name}
You can use array_reduce
array_reduce($arr, function ($acc, $x) {
return $x->name === 'abc' ? $acc + 1 : $acc;
}, 0);
// => 2
Or write it as a function
function countAttr($attr, $match, $xs) {
return array_reduce($xs, function ($acc, $x) use ($attr, $match) {
return $x->{$attr} === $match ? $acc + 1 : $acc;
}, 0);
}
countAttr('name', 'abc', $arr)(
// => 2
In this case defining a function would be best so that count for any name cen be get. You can try this -
$array = [
0 => ['name' => 'abc', 'add'=>'def', 'city'=>'ny','phone'=>'12345'],
1 => ['name' => 'pqr', 'add'=>'mno', 'city'=>'qw','phone'=>'67890'],
2 => ['name' => 'abc', 'add'=>'def', 'city'=>'ny','phone'=>'14785'],
3 => ['name' => 'ghi', 'add'=>'foo', 'city'=>'yu','phone'=>'258'],
4 => ['name' => 'jkl', 'add'=>'exy', 'city'=>'ny','phone'=>'95145'],
];
function get_name_count($array, $name)
{
// filter array for name
$temp = array_filter($array, function($a) use($name) {
return ($a['name'] === $name);
});
// return count
return count($temp);
}
var_dump(get_name_count($array, 'abc'));
Output
int(2)
// hello , please use some standard name for array
// code not tested
// define variable if required
$field_name="name";
$value="abc";
$count=0;
echo count_field($field_name,$value);
function count_field($field_name,$value)
{
foreach($hello as $val)
{
if($val[$field_name]==$value)
{
$count++;
}
}
return $count;
}
How can i merge array with the same value?
I have three array which are $participants, $conferance_participants and $contacts
i want to compare values with this three array and merge
for example :
if $participants['calleridnum'] == $conferance_participants['uid'] == $contacts['name']
i want the output to be like this :
Array
(
[0] => Array
(
[calleridnum] => 1
[test] => yay
[uid] => 1
[channel] => deze
[name] => 1
[limit] => 1
)
)
this is my code so far:
<?php
$participants = [
[ 'calleridnum' => 1,
'test' => 'yay'
]
];
$conferance_participants = [
[ 'uid' => 1,
'test' => 'yay2',
'channel' => 'deze'
]
];
$contacts = [
[ 'name' => 1,
'test' => 'yay2',
'limit' => 1
]
];
foreach ($participants as $participant=>$p) {
foreach ($conferance_participants as $conferance_participant=>$c) {
foreach ($contacts as $contact=>$cs) {
if (($p['calleridnum'] == $c['uid']) && ($c['uid'] == $cs['name'])) {
foreach ( $c as $key=>$val ) {
if (!isset($p[$key])) {
$participants[$participant][$key] = $val;
}
}
}
}
}
}
print_r( $participants );
?>
Try to call array_merge() , but you still have to consider the different values with the same key (eg. the values of key 'test' )
if (($p['calleridnum'] == $c['uid']) && ($p['uid'] == $c['name'])) {
$participants[$participant] = array_merge(
$participants[$participant],
$conferance_participants[$conferance_participant],
$contacts[$contact]
);
}
I need to merge those two arrays:
$ar1 = array("color" => array("red", "green"), "aa");
$ar2 = array("color" => array( "green", "blue"), "bb");
$result = array_merge_recursive($ar1, $ar2);
Expected output:
[
'color' => [
(int) 0 => 'red',
(int) 1 => 'green',
(int) 3 => 'blue'
],
(int) 0 => 'aa',
(int) 1 => 'bb'
]
But it outputs:
[
'color' => [
(int) 0 => 'red',
(int) 1 => 'green',
(int) 2 => 'green', (!)
(int) 3 => 'blue'
],
(int) 0 => 'aa',
(int) 1 => 'bb'
]
I'm looking for the simplest way to do this, my array inputs won't be deeper than those examples.
Here it is.
function array_merge_recursive_ex(array $array1, array $array2)
{
$merged = $array1;
foreach ($array2 as $key => & $value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = array_merge_recursive_ex($merged[$key], $value);
} else if (is_numeric($key)) {
if (!in_array($value, $merged)) {
$merged[] = $value;
}
} else {
$merged[$key] = $value;
}
}
return $merged;
}
Thanks to Meglio comment, you can use these functions for any number of arrays :
Functions
function drupal_array_merge_deep() {
$args = func_get_args();
return drupal_array_merge_deep_array($args);
}
// source : https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_array_merge_deep_array/7.x
function drupal_array_merge_deep_array($arrays) {
$result = array();
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
// Renumber integer keys as array_merge_recursive() does. Note that PHP
// automatically converts array keys that are integer strings (e.g., '1')
// to integers.
if (is_integer($key)) {
$result[] = $value;
}
elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
$result[$key] = drupal_array_merge_deep_array(array(
$result[$key],
$value,
));
}
else {
$result[$key] = $value;
}
}
}
return $result;
}
Usage
$merged = drupal_array_merge_deep($ar_1, $ar_2);
var_dump($merged);
$merged = drupal_array_merge_deep_array([$ar_1, $ar_2]);
var_dump($merged);
Usage (test data)
$ar_1 = [
"item1" => false,
"item2" => true,
"item_list" => [
"sub_item1" => 5,
"sub_itemlist" => [
"sub_sub_item1" => 27,
],
]
];
$ar_2 = [
"item_list" => [
"sub_item2" => 5,
"sub_itemlist" => [
"sub_sub_item2" => 27,
],
],
"item3" => true,
];
Usage output (same for both functions)
array (size=4)
'item1' => boolean false
'item2' => boolean true
'item_list' =>
array (size=3)
'sub_item1' => int 5
'sub_itemlist' =>
array (size=2)
'sub_sub_item1' => int 27
'sub_sub_item2' => int 27
'sub_item2' => int 5
'item3' => boolean true
I have an array which looks like this
$dataArray = array (
0 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PI',
),
1 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PM',
),
2 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A90123',
'Role' => 'CI',
),
3 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A20022',
'Role' => 'PM',
),
)
I need it to look like this
$expected = array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'PI',
),
'A20022' =>
array (
0 => 'CI',
),
),
)
I think this could be achieved generically using recursion as this is a scenario I am likely to come across many times
I have got this far passing in an array of keys that form the nested array keys i.e.
$keys=array("UserId","projectCode","Role");
but am just not seeing where to go from here any pointers?
public function structureData(array $data, array $keys)
{
//$structuredData = array();
foreach ($data as $key => $value)
{
$keyForData = array_slice($keys,0,1);
$remainingKeys = $keys;
array_shift($remainingKeys);
if (!array_key_exists($value[$keyForData[0]], $structuredData))
{
$count=count($remainingKeys);
$structuredData[$value[$keyForData[0]]] =array();
// this returns as expected array(804023 =>array ()); but subsequent recursive calls with the remaining data fail
}
}
return $structuredData);
}
You don't need recursion, just a loop:
foreach ($dataArray as $da) {
$expected[$da['UserId']][$da['ProjectCode']][] = $da['Role'];
}
var_export($expected);
/* output:
array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'CI',
),
'A20022' =>
array (
0 => 'PM',
),
),
)
*/
A crude but functioning solution.
function structureData($data, $keys){
$out = array();
foreach($data as $row){
$subout = &$out;
foreach(array_slice($keys, 0, -1) as $key){
$value = $row[$key];
$subout = &$subout[$value];
}
$subout[] = $row[$keys[count($keys) - 1]];
}
return $out;
}
print_r(structureData($dataArray, array('UserId', 'ProjectCode', 'Role')));
Recursion? Nah. Try this:
function add_role($dataArray, $userid, $project_code, $role)
{
$dataArray[$userid][$project_code][] = $role;
}
Functional solution:
$t = array_gather_key($dataArray, function ($e) { return $e['UserId']; } );
$t = array_map(
function ($e) {
return array_gather_key($e,
function ($e) { return $e['ProjectCode']; },
function ($e) { return $e['Role']; } );
},
$t
);
With this higher-order function:
function array_gather_key($array, $func, $transf = null) {
$res = array();
foreach ($array as $elem) {
$key = $func($elem);
if (!array_key_exists($key, $res))
$res[$key] = array();
if ($transf === null)
$res[$key][] = $elem;
else
$res[$key][] = $transf($elem);
}
return $res;
}
This gives:
array(1) {
[804023]=>
array(3) {
["RA1234"]=>
array(2) {
[0]=>
string(2) "PI"
[1]=>
string(2) "PM"
}
["A90123"]=>
array(1) {
[0]=>
string(2) "CI"
}
["A20022"]=>
array(1) {
[0]=>
string(2) "PM"
}
}
}