I have a list of array keys and nesting level in one array, for example:
$keys[0] = 'first';
$keys[1] = 'second';
$keys[2] = 'third';
How can I transform this into a multidimensional array in the following format:
$array['first']['second']['third'] = 'value';
I tried a couple different variations that did not work out and the keys overwrote themselves. The simplest way is to get a count of the number of keys and manually cover each scenario but this is hardly optimized and does not dynamically grow.
$keyLen = count($keys);
if ($keyLen == 1) {
$array[$keys[0]] = 'value;
} elseif ($keyLen == 2) {
$array[$keys[0]][$keys[1]] = 'value;
} elseif ($keyLen == 3) {
$array[$keys[0]][$keys[1]][$keys[2]] = 'value';
} ...
A couple notes, the value is not of significance it's the nesting of the array keys, and I cannot change the initial array format.
You could go backwards through your input array and wrap the previous result as you go:
$nested = 'value';
for (end($keys); key($keys)!==null; prev($keys)){
$nested = [current($keys) => $nested];
}
At the end $nested will have the desired structure.
Give this a try. Here we're using references to stack our new arrays.
<?php
$keys = array('first', 'second', 'third');
$array = array();
$current = &$array;
foreach($keys as $key => $value) {
$current[$value] = array();
$current = &$current[$value];
}
$current = 'Hello world!';
print_r($array);
Starting from the last Item you can loop through the array, pop the last one and build the new array:
<?php
$keys[0] = 'first';
$keys[1] = 'second';
$keys[2] = 'third';
function createKey($array) {
$b = "value";
while(count($array)>0) {
$key = array_pop($array);
$b = [$key => $b];
}
return $b;
}
var_dump(createKey($keys));
// Output:
array(1) {
["first"]=>
array(1) {
["second"]=>
array(1) {
["third"]=>
string(5) "value"
}
}
}
Another option is to loop the reversed keys and wrap the previous result:
$array = [];
foreach(array_reverse($keys) as $key) {
$temp = $array;
unset($array[key($array)]);
$array[$key] = $temp;
}
Then you could set your value:
$array['first']['second']['third'] = 'value';
Demo
You could even eval this in a safe way without leaking any input data into the eval-string:
$value = 'value';
eval( '$array[$keys['. implode(']][$keys[', range(0, count($keys)-1)) . ']] = $value;' );
or with an additional counter even simpler and shorter:
$value = 'value';
$i = 0;
eval( '$array' . str_repeat('[$keys[$i++]]', count($keys)) . ' = $value;' );
Related
My problem is relatively simple but I cannot figure it out a reasonable algorithm by myself
I have an array which can be any length (n>=2), and I want to connect the elements with 2 separators ( '_' and '+' ):
So for example when my array has 2 elements [0,1] the result would be
[0_1, 0+1]
For 3 elements [0,1,2]
0_1_2,
0+1+2,
0+1_2,
0_1+2,
0_2+1
For 4 elements [0,1,2,3]
0_1_2_3,
0+1+2+3,
0+1_2_3,
0_1+2_3,
0_1_2+3,
0_2+1+3,
0_2+1_3,
0_3+1+2,
0_3+1_2
For 5 elements [0,1,2,3,4]
0_1_2_3_4,
0+1_2_3_4,
0_1+2_3_4,
0_1_2+3_4,
0_1_2_3+4,
0+1+2+3+4,
0_2+1+3+4,
0_2+1_3_4,
0_2+1+3_4,
0_2+1_3+4,
...
I hope this explanation is somewhat clear.
Not sure if this hits spec, but its a start:
$new = [];
$arr = [1,2,3,4,5];
for($i=0;$i<count($arr);$i++) {
$new[] = implode("_",$arr);
$arr[] = array_shift($arr);
}
foreach($new as $n) {
$o = $n;
while(strpos($o,"_")) {
$o = preg_replace("/_/","+",$o,1);
$new[] = $o;
}
$o = strrev($n);
while(strpos($o,"_")) {
$o = preg_replace("/_/","+",$o,1);
$new[] = $o;
}
}
print_r($new);
I want to combine two arrays into a dictionary.
The keys will be the distinct values of the first array, the values will be all values from the second array, at matching index positions of the key.
<?php
$a=[2,3,4,5,6,7,8,9,10];
$b=[1,1,3,2,1,2,6,8,8];
?>
array_combine($b,$a);
Expected result as
<?php
/*
Value '1' occurs at index 0, 1 and 4 in $b
Those indices map to values 2, 3 and 6 in $a
*/
$result=[1=>[2,3,6],3=>4,2=>[5,7],6=>8,8=>[9,10]];
?>
There are quite a few PHP array functions. I'm not aware of one that solves your specific problem. you might be able to use some combination of built in php array functions but it might take you a while to weed through your choices and put them together in the correct way. I would just write my own function.
Something like this:
function myCustomArrayFormatter($array1, $array2) {
$result = array();
$num_occurrences = array_count_values($array1);
foreach ($array1 AS $key => $var) {
if ($num_occurrences[$var] > 1) {
$result[$var][] = $array2[$key];
} else {
$result[$var] = $array2[$key];
}
}
return $result;
}
hope that helps.
$a=[2,3,4,5,6,7,8,9,10];
$b=[1,1,3,2,1,2,6,8,8];
$results = array();
for ($x = 0; $x < count($b); $x++) {
$index = $b[$x];
if(array_key_exists ($index, $results)){
$temp = $results[$index];
}else{
$temp = array();
}
$temp[] = $a[$x];
$results[$index] = $temp;
}
print_r($results);
Here's one way to do this:
$res = [];
foreach ($b as $b_index => $b_val) {
if (!empty($res[$b_val])) {
if (is_array($res[$b_val])) {
$res[$b_val][] = $a[$b_index];
} else {
$res[$b_val] = [$res[$b_val], $a[$b_index]];
}
} else {
$res[$b_val] = $a[$b_index];
}
}
var_dump($res);
UPDATE: another way to do this:
$val_to_index = array_combine($a, $b);
$result = [];
foreach ($val_to_index as $value => $index) {
if(empty($result[$index])){
$result[$index] = $value;
} else if(is_array($result[$index])){
$result[$index][] = $value;
} else {
$result[$index] = [$result[$index], $value];
}
}
var_dump($result);
I have two arrays of associative arrays with different keys. I need to merge them into a single array of associative arrays, with nulls or empty strings for keys that do not exist at higher indices. For example:
$first = array(array('x'=>'1','y'=>'2'));
$second = array(array('z'=>'3'),array('z'=>'4'));
The result should look like this:
$result = array(
array(
'x'=>'1',
'y'=>'2',
'z'=>'3'
),
array(
'x'=>'',
'y'=>'',
'z'=>'4'
)
);
The function that merges these arrays needs to be able to handle two or more arrays. Here's what I came up with:
// allArrays can be many arrays of all sizes and will be different each time this process runs
$allArrays = array($first, $second);
$longestArray = max($allArrays);
$data = array();
for($i = 0; $i < count($longestArray); ++$i) {
$dataRow = array();
foreach ($allArrays as $currentArray) {
if (isset($currentArray[$i])) {
foreach ($currentArray[$i] as $key => $value) {
$dataRow[$key] = $value;
}
} else {
foreach ($currentArray[0] as $key => $value) {
$dataRow[$key] = '';
}
}
}
$data[] = $dataRow;
}
It works, but I think the nested for loops cause poor performance on large arrays, and it's pretty illegible. Is there a better way to tackle this problem?
Unfortunately, it looks like this is the best way to solve this problem. I'll answer the question with the example from above in case it helps anyone in the future.
// allArrays can be many arrays of all sizes and will be different each time this process runs
$allArrays = array($first, $second);
$longestArray = max($allArrays);
$data = array();
for($i = 0; $i < count($longestArray); ++$i) {
$dataRow = array();
foreach ($allArrays as $currentArray) {
if (isset($currentArray[$i])) {
foreach ($currentArray[$i] as $key => $value) {
$dataRow[$key] = $value;
}
} else {
foreach ($currentArray[0] as $key => $value) {
$dataRow[$key] = '';
}
}
}
$data[] = $dataRow;
}
I would like to create a clone function on the following array,
$usernames = array ( 'jack', 'amy', 'chris');
such that:
Cloning jack, would result in jack-1 (because jack-1 does not exist in usernames array yet). Once cloned, the usernames array should be updated to:
$usernames = array ( 'jack', 'amy', 'chris', 'jack-1');
Cloning jack, (again) would result in jack-2
Cloning jack-1, would result in jack-1-1
Cloning jack-1-1, would result in jack-1-1-1
Cloning jack-1-1 (again), would result in jack-1-1-2
Cloning jack-1-1-1 would result in jack-1-1-1-1
and so on and so forth..
I can work with in_array to do this, but looking for an efficient way to do this.
Thanks,
I've tested this and it works.
First, we check if the the value already exists, if it doesn't, we just go ahead and add it.
If it does exist, we add the incrementing number with a dash to it. We keep incrementing until we get to one that doesn't exist...then we add it.
<?php
$array = ['jack', 'sally'];
function cloneFunction($value, $array)
{
if (!in_array($value, $array))
{
$array[] = $value;
}
else
{
$i = 0;
while(in_array($value, $array))
{
$i++;
$value = $value . '-' . $i;
}
$array[] = $value;
}
return $array;
// Do return $value if you just want the value.
}
print_r(cloneFunction('jack', $array));
Based on Sajan's Logic, it works according to the requirement, if I modify the logic this way. Copying the original username and re-parsing the original array, does the trick.
$array = array('jack', 'sally');
function cloneFunction($value, $array)
{
if (!in_array($value, $array))
{
$array[] = $value;
}
else
{
$i = 0;
$j = 0;
while(in_array($value, $array))
{
$i++;
$value = $value . '-' . $i;
$stagedValue = $value;
while(in_array($value, $array))
{
$j++;
$value = $stagedValue . '-' . $j;
}
$j = $i;
}
$array[] = $value;
}
return $array;
// Do return $value if you just want the value.
}
print_r(cloneFunction('jack', $array));
Let's say i have this array:
$array = (1,2,4,5);
Now how do i add missing 3 in above array in the correct position index/key-wise?
Try:
array_splice($array, 2 /*offset*/, 0 /*length*/, 3 /*value*/);
Note that this will reorder the input array's keys from 0 to n-1.
(Edit: The return value is not used in this case.)
array_merge(array_slice($array,0,2),array(3),array_slice($array,2))
Maybe I'm missing the complexity of your question, but doesn't the following give you what you want?
$array[] = 3;
sort($array);
Last but not least:
Append new stuff at the end of the array
Sort the array when you finally need it: asort()
function insertMissingIntoArray($values = array(), $valueIncrement = 1) {
$lastValue = 0;
foreach ($values as $key=>$val) {
if ($key != 0) {
if ($val != $lastValue + $valueIncrement) {
array_splice($values, $key, 0, $val);
}
$lastValue = $val;
}
}
return $values;
}
Used like this:
$values = array(1,2,4,5,7,9);
$fixedValues = insertMissingIntoArray($values, 1);
// $fixedValues now is (1,2,3,4,5,6,7,8,9)
function array_insert($array,$pos,$val)
{
$array2 = array_splice($array,$pos);
$array[] = $val;
$array = array_merge($array,$array2);
return $array;
}
usage:
array_insert($a,2,3);