How can I merge two arrays (one with string => value pairs and another with int => value pairs) while keeping the string/int keys? None of them will ever overlap (because one has only strings and the other has only integers).
Here is my current code (which doesn't work, because array_merge is re-indexing the array with integer keys):
// get all id vars by combining the static and dynamic
$staticIdentifications = array(
Users::userID => "USERID",
Users::username => "USERNAME"
);
// get the dynamic vars, formatted: varID => varName
$companyVarIdentifications = CompanyVars::getIdentificationVarsFriendly($_SESSION['companyID']);
// merge the static and dynamic vars (*** BUT KEEP THE INT INDICES ***)
$idVars = array_merge($staticIdentifications, $companyVarIdentifications);
You can simply 'add' the arrays:
>> $a = array(1, 2, 3);
array (
0 => 1,
1 => 2,
2 => 3,
)
>> $b = array("a" => 1, "b" => 2, "c" => 3)
array (
'a' => 1,
'b' => 2,
'c' => 3,
)
>> $a + $b
array (
0 => 1,
1 => 2,
2 => 3,
'a' => 1,
'b' => 2,
'c' => 3,
)
Considering that you have
$replaced = array('1' => 'value1', '4' => 'value4');
$replacement = array('4' => 'value2', '6' => 'value3');
Doing $merge = $replacement + $replaced; will output:
Array('4' => 'value2', '6' => 'value3', '1' => 'value1');
The first array from sum will have values in the final output.
Doing $merge = $replaced + $replacement; will output:
Array('1' => 'value1', '4' => 'value4', '6' => 'value3');
I just want to add another possibility of doing a merge while keeping keys.
Besides adding key/values to existing arrays using the + sign you could do an array_replace.
$a = array('foo' => 'bar', 'some' => 'string', 'me' => 'is original');
$b = array(42 => 'answer to the life and everything', 1337 => 'leet', 'me' => 'is overridden');
$merged = array_replace($a, $b);
The result will be:
Array
(
[foo] => bar
[some] => string
[me] => is overridden
[42] => answer to the life and everything
[1337] => leet
)
Same keys will be overwritten by the latter array.
There is also an array_replace_recursive, which do this for subarrays, too.
Live example on 3v4l.org
Two arrays can be easily added or union without chaning their original indexing by + operator. This will be very help full in laravel and codeigniter select dropdown.
$empty_option = array(
''=>'Select Option'
);
$option_list = array(
1=>'Red',
2=>'White',
3=>'Green',
);
$arr_option = $empty_option + $option_list;
Output will be :
$arr_option = array(
''=>'Select Option'
1=>'Red',
2=>'White',
3=>'Green',
);
The OP.'s requirement is to preserve keys (keep keys) and not overlap (I think overwrite). In some cases such as numeric keys it is possible but if string keys it seems to be not possible.
If you use array_merge() the numeric keys will always re-index or renumbered.
If you use array_replace(), array_replace_recursive() it will be overlap or overwrite from the right to the left. The value with the same key on first array will be replaced with second array.
If you use $array1 + $array2 as the comment was mentioned, if the keys are same then it will keep the value from first array but drop the second array.
Custom function.
Here is my function that I just wrote to work on the same requirements. You are free to use for any purpose.
/**
* Array custom merge. Preserve indexed array key (numbers) but overwrite string key (same as PHP's `array_merge()` function).
*
* If the another array key is string, it will be overwrite the first array.<br>
* If the another array key is integer, it will be add to first array depend on duplicated key or not.
* If it is not duplicate key with the first, the key will be preserve and add to the first array.
* If it is duplicated then it will be re-index the number append to the first array.
*
* #param array $array1 The first array is main array.
* #param array ...$arrays The another arrays to merge with the first.
* #return array Return merged array.
*/
function arrayCustomMerge(array $array1, array ...$arrays): array
{
foreach ($arrays as $additionalArray) {
foreach ($additionalArray as $key => $item) {
if (is_string($key)) {
// if associative array.
// item on the right will always overwrite on the left.
$array1[$key] = $item;
} elseif (is_int($key) && !array_key_exists($key, $array1)) {
// if key is number. this should be indexed array.
// and if array 1 is not already has this key.
// add this array with the key preserved to array 1.
$array1[$key] = $item;
} else {
// if anything else...
// get all keys from array 1 (numbers only).
$array1Keys = array_filter(array_keys($array1), 'is_int');
// next key index = get max array key number + 1.
$nextKeyIndex = (intval(max($array1Keys)) + 1);
unset($array1Keys);
// set array with the next key index.
$array1[$nextKeyIndex] = $item;
unset($nextKeyIndex);
}
}// endforeach; $additionalArray
unset($item, $key);
}// endforeach;
unset($additionalArray);
return $array1;
}// arrayCustomMerge
Testing.
<?php
$array1 = [
'cat',
'bear',
'fruitred' => 'apple',
3 => 'dog',
null => 'null',
];
$array2 = [
1 => 'polar bear',
20 => 'monkey',
'fruitred' => 'strawberry',
'fruityellow' => 'banana',
null => 'another null',
];
// require `arrayCustomMerge()` function here.
function printDebug($message)
{
echo '<pre>';
print_r($message);
echo '</pre>' . PHP_EOL;
}
echo 'array1: <br>';
printDebug($array1);
echo 'array2: <br>';
printDebug($array2);
echo PHP_EOL . '<hr>' . PHP_EOL . PHP_EOL;
echo 'arrayCustomMerge:<br>';
$merged = arrayCustomMerge($array1, $array2);
printDebug($merged);
assert($merged[0] == 'cat', 'array key 0 should be \'cat\'');
assert($merged[1] == 'bear', 'array key 1 should be \'bear\'');
assert($merged['fruitred'] == 'strawberry', 'array key \'fruitred\' should be \'strawberry\'');
assert($merged[3] == 'dog', 'array key 3 should be \'dog\'');
assert(array_search('another null', $merged) !== false, '\'another null\' should be merged.');
assert(array_search('polar bear', $merged) !== false, '\'polar bear\' should be merged.');
assert($merged[20] == 'monkey', 'array key 20 should be \'monkey\'');
assert($merged['fruityellow'] == 'banana', 'array key \'fruityellow\' should be \'banana\'');
The results.
array1:
Array
(
[0] => cat
[1] => bear
[fruitred] => apple
[3] => dog
[] => null
)
array2:
Array
(
[1] => polar bear
[20] => monkey
[fruitred] => strawberry
[fruityellow] => banana
[] => another null
)
---
arrayCustomMerge:
Array
(
[0] => cat
[1] => bear
[fruitred] => strawberry
[3] => dog
[] => another null
[4] => polar bear
[20] => monkey
[fruityellow] => banana
)
Try array_replace_recursive or array_replace functions
$a = array('userID' => 1, 'username'=> 2);
array (
userID => 1,
username => 2
)
$b = array('userID' => 1, 'companyID' => 3);
array (
'userID' => 1,
'companyID' => 3
)
$c = array_replace_recursive($a,$b);
array (
userID => 1,
username => 2,
companyID => 3
)
http://php.net/manual/en/function.array-replace-recursive.php
Related
my 1st array values are
Array (
[0] => abc
[1] => xyz
[2] => Other
[3] => Other
[4] => pqr )
when array contains value as Other i want to replace that with below array
Array (
[0] => lmnsa
[1] => asda )
I want to do this in PHP. any help guys?
First loop over the array1 and test for the value 'Other', if found replace the value with your array2
Note the use of &$a to make the $a from the foreach loop a reference, so that it can be used to replace the original array occurance and not a copy of the array which woudl have been the result without the use of the &
$array1 = Array ( "abc","xyz","Other", "Other", "pqr" );
$array2 = Array ( "lmnsa", "asda" );
foreach ($array1 as &$a) {
if ( $a == 'Other') {
$a = $array2;
}
}
print_r($array1);
The RESULT
Array
(
[0] => abc
[1] => xyz
[2] => Array
(
[0] => lmnsa
[1] => asda
)
[3] => Array
(
[0] => lmnsa
[1] => asda
)
[4] => pqr
)
I don't really understand what result are you looking for.
If you want to just replace elements with value 'Other' with some different value:
$newValue = 'New value instead of Other';
// $newValue = ['abc' 'def']; <-- if you want to replace string by an array. It wasn't unclear what you expect to achieve from the question.
$array = ['a', 'b', 'Other', 'c', 'Other', 'd'];
foreach ($array as $idx => $element) {
if ($element === 'Other') {
$array[$idx] = $newValue;
}
}
Or if you have an array of replacements, which must gradually replace all 'Other' values:
$array = ['a', 'b', 'Other', 'c', 'Other', 'd'];
$replacements = ['New Value 1', 'New Value 2'];
$replacementIdx = 0;
foreach ($array as $idx => $element) {
// Always check if you were not run out of replacement values
if (!isset($replacements[$replacementIdx])) {
break;
}
if ($element === 'Other') {
$array[$idx] = $replacements[$replacementIdx++];
}
}
Instead of using foreach ($array as $key => $value) you may also try to replace elements by reference (see RiggsFolly answer)
Based on your request what Yamingue stated is correct. You may need to clarify what you want. Are you attempting to say if the indexed value of the array initial array is 2 and its value is "Other" to replace it with it with the equivalent value of another array with the same index number?
Its been a while since ive done php buy lets give this a go.
$array1 = Array (
0 => "abc"
1 => "xyz"
2 => "Other"
3 => "Other"
4 => "pqr" );
$array2 = Array (
0 => "lmnsa"
1 => "asda"
2 => "thg"
3 => "ris"
4 => "slrn");
Foreach($array1 as $arr1key => $arr1val) {
If($arr1val == "Other"){
$array1[$arr1key] = $array2[$arr1key];
}
}
You may need to unset the values however as i said been a while for me. Nowbif you want to embed the 2nd array into the value of the first array where it currently says other thats another story, each language is a little different on multidimensional and nested arrays so i cant speak to it.
there are several ways to do it as needed. the first is to replace it with another array like this
`
$array1 = Array (
0 => "abc"
1 => "xyz"
2 => "Other"
3 => "Other"
4 => "pqr" );
$array2 = Array (
0 => "lmnsa"
1 => "asda" );
$array1 = $array2
`
I have array something like:
Array (
[0]=>{"a":"b", "c":"d", "h":"e"}
[1]=>{"a":"b", "f":"g"}
)
How i can removing duplicates here? I'm trying array_unique, but it's not working.
Expected result:
Array (
[0]=>{"a":"b", "c":"d", "h":"e"}
[1]=>{"f":"g"}
)
In this scenario, you need to be careful with duplicate keys yet different values. So match to remove duplicates has to be on combination of both key and value.
To do this, we can collect all keys in an array say $map and have all values visited for this keys inside that key array.
Now, we can just do an in_array check to get hold of whether we got some key-value pair like this before or not.
Snippet:
$arr = [
[
'a' => 'b',
'c' => 'd',
'h' => 'e'
],
[
'a' => 'b',
'f' => 'g',
'c' => 'f'
],
[
'a' => 'd',
'c' => 'd'
]
];
$map = [];
foreach($arr as $index => $data){
foreach($data as $key => $value){
if(!isset($map[$key])) $map[$key] = [];
if(in_array($value,$map[$key])) unset($arr[$index][$key]);
else $map[$key][] = $value;
}
}
print_r($arr);
Demo: https://3v4l.org/RWcMu
You can do it with array_diff() and unset() functions. But, you need to decode this JSON values firstly:
foreach($ar as $in => &$js){
$ar[$in] = json_decode($js,true);
}
After this $ar has a view like:
Array
(
[0] => Array
(
[a] => b
[c] => d
[h] => e
)
[1] => Array
(
[a] => b
[f] => g
)
)
Here you can apply array_diff() function:
$diff = array_diff($ar[1],array_diff($ar[1],$ar[0]));
It will collect duplicates from [1] index in [0]:
Array
(
[a] => b
)
Now you can unset these values from [1] index:
foreach($diff as $ind=>$uns){
unset($ar[1][$ind]);
}
And finally you can change JSON view back:
foreach($ar as $in=>&$js){
$ar[$in] = json_encode($js);
}
Result would be:
Array
(
[0] => {"a":"b","c":"d","h":"e"}
[1] => {"f":"g"}
)
Demo
If input elements are objects, then use this loop at the first step:
foreach($ar as $in=>&$obj){
$ar[$in] = (array)$obj;
}
Demo
I had 2 array with different number of key
First array:
0 =>
array (size=2)
'a' => 1
'b' => 'b'
1 =>
array (size=2)
'a' => 2
'b' => '2b'
Second array:
0 =>
array (size=2)
'a' => 1
'c' => 'c'
The 'a' is act like id but there is problem on 'b' and 'c' are not mandatory to list out.
I tried array_merge before but it quite complex for my next step so i want to know is there others solution for this?
I also tried the foreach loop but it stuck at:
foreach($first_array as $data){
$result[] = $data;
......
}
The output should like this form:
[0] => Array
(
[a] => 1,
[b] => 'b',
[c] => 'c',
)
[1] => Array
(
[a] => 2,
[b] => '2b',
)
If 'a' contains the id of the record, it would be a good idea to use this as an identifier in the result array.
$results = [];
$dataSets = [$first_array, $second_array];
foreach ($dataSets as $dataSet) {
foreach ($dataSet as $record) {
if (!isset($results[$record['a']]) {
// first occurence of this record
$results[$record['a']] = $record;
continue;
}
// next occurence of this record, merge it with existing data
$results[$record['a']] = array_merge($results[$record['a']], $record);
}
}
If the results should be a normal array (e.g. if you want to encode it to JSON and don't want an object), you'll still need to remove the ids at the end
$results = array_values($results);
It is better to use a multi-dimensional array.
For example:
$myarray = array(
array("1", "b", "c"),
array("2", "2b")
);
This is one array
Array ( [0] => 1 [1] => 2 )
The associative array is
Array ( [0] => Array ( [id_1] => 3 [id_2] => 1 ) [1] => Array ( [id_3] => 5 [id_4] => 3 ) )
I want to compare these arrays and get an array containing the values that are not present in the associative array
The result should be array(3) and array(5,3)
$array1 = array(1,2);
$array2 = array(
array(
'id_1' => 3,
'id_2' => 1
),
array(
'id_3' => 5,
'id_4' => 3,
)
);
I'm not sure if I understand the question, if you want to compare each array individually:
foreach($array2 as $subarray) {
var_dump(array_diff($subarray, $array1));
}
returns:
array
'id_1' => int 3
array
'id_3' => int 5
'id_4' => int 3
Otherwise if you don't want to loop through and flatten the array (using an array_flatten function from the php doc comments of array_values)
http://www.php.net/manual/en/function.array-values.php#97715
function array_flatten($a,$f=array()){
if(!$a||!is_array($a))return '';
foreach($a as $k=>$v){
if(is_array($v))$f=array_flatten($v,$f);
else $f[$k]=$v;
}
return $f;
}
var_dump(
array_unique(
array_diff(
array_flatten($array2), $array1
)
)
);
returns:
array
'id_1' => int 3
'id_3' => int 5
'id_4' is not shown because it doesn't have a unique value. You can remove the keys with array_values() or leave in 'id_4' by removing the array_unique() from the code.
something like this, maybe?
$array_a = array(1, 2);
$array_b = array(array(1, 3), array(3, 1));
$result = array();
foreach($array_b as $key => $sub_array_b){
foreach($sub_array_b as $sub_key => $value){
if(!in_array($value, $array_a) && !in_array($value, $result)) array_push($result, $value);
}
}
EDIT: I typed this before you edited your question. You can still modify the code above so that it creates a different array for each subarray in your associative array.
I have the following array, which I would like to reindex so the keys are reversed (ideally starting at 1):
Current array (edit: the array actually looks like this):
Array (
[2] => Object
(
[title] => Section
[linked] => 1
)
[1] => Object
(
[title] => Sub-Section
[linked] => 1
)
[0] => Object
(
[title] => Sub-Sub-Section
[linked] =>
)
)
How it should be:
Array (
[1] => Object
(
[title] => Section
[linked] => 1
)
[2] => Object
(
[title] => Sub-Section
[linked] => 1
)
[3] => Object
(
[title] => Sub-Sub-Section
[linked] =>
)
)
If you want to re-index starting to zero, simply do the following:
$iZero = array_values($arr);
If you need it to start at one, then use the following:
$iOne = array_combine(range(1, count($arr)), array_values($arr));
Here are the manual pages for the functions used:
array_values()
array_combine()
range()
Why reindexing? Just add 1 to the index:
foreach ($array as $key => $val) {
echo $key + 1, '<br>';
}
Edit After the question has been clarified: You could use the array_values to reset the index starting at 0. Then you could use the algorithm above if you just want printed elements to start at 1.
This will do what you want:
<?php
$array = array(2 => 'a', 1 => 'b', 0 => 'c');
array_unshift($array, false); // Add to the start of the array
$array = array_values($array); // Re-number
// Remove the first index so we start at 1
$array = array_slice($array, 1, count($array), true);
print_r($array); // Array ( [1] => a [2] => b [3] => c )
?>
You may want to consider why you want to use a 1-based array at all. Zero-based arrays (when using non-associative arrays) are pretty standard, and if you're wanting to output to a UI, most would handle the solution by just increasing the integer upon output to the UI.
Think about consistency—both in your application and in the code you work with—when thinking about 1-based indexers for arrays.
You can reindex an array so the new array starts with an index of 1 like this;
$arr = array(
'2' => 'red',
'1' => 'green',
'0' => 'blue',
);
$arr1 = array_values($arr); // Reindex the array starting from 0.
array_unshift($arr1, ''); // Prepend a dummy element to the start of the array.
unset($arr1[0]); // Kill the dummy element.
print_r($arr);
print_r($arr1);
The output from the above is;
Array
(
[2] => red
[1] => green
[0] => blue
)
Array
(
[1] => red
[2] => green
[3] => blue
)
Well, I would like to think that for whatever your end goal is, you wouldn't actually need to modify the array to be 1-based as opposed to 0-based, but could instead handle it at iteration time like Gumbo posted.
However, to answer your question, this function should convert any array into a 1-based version
function convertToOneBased( $arr )
{
return array_combine( range( 1, count( $arr ) ), array_values( $arr ) );
}
EDIT
Here's a more reusable/flexible function, should you desire it
$arr = array( 'a', 'b', 'c' );
echo '<pre>';
print_r( reIndexArray( $arr ) );
print_r( reIndexArray( $arr, 1 ) );
print_r( reIndexArray( $arr, 2 ) );
print_r( reIndexArray( $arr, 10 ) );
print_r( reIndexArray( $arr, -10 ) );
echo '</pre>';
function reIndexArray( $arr, $startAt=0 )
{
return ( 0 == $startAt )
? array_values( $arr )
: array_combine( range( $startAt, count( $arr ) + ( $startAt - 1 ) ), array_values( $arr ) );
}
A more elegant solution:
$list = array_combine(range(1, count($list)), array_values($list));
The fastest way I can think of
array_unshift($arr, null);
unset($arr[0]);
print_r($arr);
And if you just want to reindex the array(start at zero) and you have PHP +7.3 you can do it this way
array_unshift($arr);
I believe array_unshift is better than array_values as the former does not create a copy of the array.
Changelog
Version
Description
7.3.0
This function can now be called with only one parameter. Formerly, at least two parameters have been required.
-- https://www.php.net/manual/en/function.array-unshift.php#refsect1-function.array-unshift-changelog
$tmp = array();
foreach (array_values($array) as $key => $value) {
$tmp[$key+1] = $value;
}
$array = $tmp;
It feels like all of the array_combine() answers are all copying the same "mistake" (the unnecessary call of array_values()).
array_combine() ignores the keys of both parameters that it receives.
Code: (Demo)
$array = [
2 => (object)['title' => 'Section', 'linked' => 1],
1 => (object)['title' => 'Sub-Section', 'linked' => 1],
0 => (object)['title' => 'Sub-Sub-Section', 'linked' => null]
];
var_export(array_combine(range(1, count($array)), $array));
Output:
array (
1 =>
(object) array(
'title' => 'Section',
'linked' => 1,
),
2 =>
(object) array(
'title' => 'Sub-Section',
'linked' => 1,
),
3 =>
(object) array(
'title' => 'Sub-Sub-Section',
'linked' => NULL,
),
)
If you are not trying to reorder the array you can just do:
$array = array_reverse( $array );
and then call it once more to get it back to the same order:
$array = array_reverse( $array );
array_reverse() reindexes as it reverses. Someone else showed me this a long time ago. So I can't take credit for coming up with it. But it is very simple and fast.
The result is an array with indexed keys starting from 0. https://3v4l.org/iQgVh
array (
0 =>
(object) array(
'title' => 'Section',
'linked' => 1,
),
1 =>
(object) array(
'title' => 'Sub-Section',
'linked' => 1,
),
2 =>
(object) array(
'title' => 'Sub-Sub-Section',
'linked' => NULL,
),
)
Here's my own implementation. Keys in the input array will be renumbered with incrementing keys starting from $start_index.
function array_reindex($array, $start_index)
{
$array = array_values($array);
$zeros_array = array_fill(0, $start_index, null);
return array_slice(array_merge($zeros_array, $array), $start_index, null, true);
}