Using the numbers from $ids, I want to pull the data from $nuts.
So for example:
$ids = [0,3,5]; // 0 calories, 3 sugar, 5 fat
$nuts = [
'calories' => 'cal',
'protein' => 'pro',
'carbohydrate' => 'car',
'sugar' => 'sug',
'fiber' => 'fib',
'fat' => 'fat',
];
$returnData = [
'calories' => 'cal',
'sugar' => 'sug',
'fat' => 'fat',
];
I could loop through each $ids number with a foreach(); but I'm curious to see if there is a better method than this?
$newNuts = array_values(array_flip($nuts));
foreach($ids as $i)
$returnData[$newNuts[$i]] = $nuts[$newNuts[$i]];
I did some work and realized, you don't need array_flip, array_values is fine.
$num_nuts = array_values ($nuts);
for ($z=0; $z<sizeof($ids); $z++) {
echo $num_nuts[$ids[$z]];
}
Just 1 more line of code, but I think it does the job. I think mine is going to be faster because the array_flip basically exchanges all keys with their associated values in an array, which is not what I am doing. It's actually one less pain.
I am simply converting the original array to a new one by index and simply looping upon it. Also, not the elegant way to use the power of PHP available to us, but works just fine. array_flip is O(n), but I think better not use it for larger data-sets.
How about a simple array_slice?
$result = array();
foreach ($ids as $i) {
$result += array_slice($nuts, $i, 1, true);
}
No need to create a copy of the array.
Related
I have two arrays, for example $session and $post with 100+ values. I will compare the $post array values with $session array. If post is different then it will be taken to result array else not.
We can try this using array_diff_assoc($post, $session) and foreach(). Which one is faster?
For profiling, Phil has suggested a great way in his reply, but I will link it here too, just in case:
Simplest way to profile a PHP script
Practically, you need to know what each approach does. in array_diff_assoc, you are returning the difference between 2 collections, after comparing the key/value couples for each element. It will then return an array that contains the entries from array1 that are not present in array2 or array3, etc.
In a for each loop, you will need to hard code the same function (assuming that's what you need). You will need to take the first element, then look for the combination in your other arrays. If it matches your requirements, you will save it into your output array, or even print it directly.
Same principles apply, but then again, it will be up to profiling to determine the faster approach. Try doing so on a large number of big arrays, as the difference isn't noticeable at smaller scales.
I'll leave this as a stub/example, please edit, or use for profiling.
<?php
$before = [
'name' => 'Bertie',
'age' => '23'
];
$after = [
'name' => 'Harold',
'age' => '23',
'occupation' => 'Bus driver'
];
function changed_1($after, $before) {
return array_diff_assoc($after, $before);
}
function changed_2($after, $before) {
$changed = [];
foreach($after as $k => $v) {
if(isset($before[$k]) && $before[$k] !== $v)
$changed[$k] = $v;
if(!isset($before[$k]))
$changed[$k] = $v;
}
return $changed;
}
var_export(changed_1($after, $before));
var_export(changed_2($after, $before));
Output:
array (
'name' => 'Harold',
'occupation' => 'Bus driver',
)array (
'name' => 'Harold',
'occupation' => 'Bus driver',
)
I have three arrays, say multiarray, valsarray, and otherarray. otherarray is a multidimensional array that supplies values to multiarray and valsarray, but besides that it is unimportant here. valsarray takes values from a subarray of each value in otherarray and multiarray takes straight values from otherarray, as demonstrated below:
foreach($otherarray as $other){
foreach($other as $sub){
$valsarray[] = $sub
}
$multiarray[] = array('Val1' => $other['Val1'], 'Val2' => $other['Val2']);
}
Now what I would like to do is append each key/value pair in valsarray to the current array entry of multiarray, to achieve a result similar to:
$multiarray = array('Val1' => $other['Val1'], 'Val2' => $other['Val2'],
'VALSARRAY_KEY1' => VALSARRAY_VALUE1, ..., 'VALSARRAY_KEYN' => VALSARRAY_VALUEN)
I have attempted to solve this using current in the following fashion:
foreach($valsarray as $key => $val){
current($multiarray)[$key] = $val;
}
But the multiarray remained unaltered. I may be misunderstanding how current works, or how to approach this problem, so any help or direction would be appreciated.
EDIT- EXAMPLE
otherarray = array(...prior array entries...,
array('Val1' => 'abc',
'Val2' => 'cde',
'Val3' => 'not important',
'Val4' => array(0 => 'subA', 1 => 'subB'),
...next array entries...);
BEFORE MERGE:
multiarray = array(...prior entries...,
array('Val1' => 'abc',
'Val2' => 'cde'));
valsarray = array(0 => 'subA', 1 => 'subB');
AFTER MERGE:
multiarray = array(...prior entries...,
array('Val1' => 'abc',
'Val2' => 'cde',
0 => 'subA',
1 => 'subB'));
So if multiarray was a regular array instead of a multidimensional one, I would do something like:
foreach($valsarray as $key => $val){
$multiarray[$key] = $val;
}
To achieve the end result.
I am not 100% sure what you are trying to accomplish a Minimal, Complete, and Verifiable example may help if I have misunderstood something.
It appears that the current() function does not work as you assume. (Or more specifically, the internal pointer.)
If you look at the example in the PHP documentation: Current(), you will see that for current($array) to change elements, you need to call next($array) or prev($array).
These function move the internal pointer of the array.
Note that in PHP 5, foreach loops use the internal pointer (and reset it when you start a loop), but in PHP 7, foreach loops do not use the internal pointer.
Anyway, here is my best guess at what could help you.
$valsarray_index = 0;
foreach ($otherarray as $other) {
$multiarray_value = array('Val1' => $other['Val1'], 'Val2' => $other['Val2']);
foreach ($other as $sub) {
$multiarray_value[$valsarray_index] = $sub;
// $multiarray_value["VALSARRAY_KEY" . $valsarray_index] = $sub;
$valsarray[] = $sub;
$valsarray_index += 1; // This stays in lockstep with the last index of $valsarray
}
$multiarray[] = $multiarray_value;
}
I am not exactly sure about what you want the final output to look like. If this produces incorrect information, then if would be helpful to provide some specific arrays for input and what you expect as output.
So I have a result from a form post that looks like this:
$data = [
'id_1' => [
'0' => 1,
'1' => 2
],
'id_2' => [
'0' => 3,
'1' => 4
],
'id_3' => [
'0' => 5,
'1' => 6
]
];
What I want to achieve is to split this array into two different arrays like this:
$item_1 = [
'id_1' => 1,
'id_2' => 3,
'id_3' => 5
]
$item_2 = [
'id_1' => 2,
'id_2' => 4,
'id_3' => 6
]
I've tried using all of the proper array methods such as array_chunk, array_merge with loops but I can't seem to get my mind wrapped around how to achieve this. I've seen a lot of similar posts where the first keys doesn't have names like my array does (id_1, id_2, id_3). But in my case the names of the keys are crucial since they need to be set as the names of the keys in the individual arrays.
Much shorter than this will be hard to find:
$item1 = array_map('reset', $data);
$item2 = array_map('end', $data);
Explanation
array_map expects a callback function as its first argument. In the first line this is reset, so reset will be called on every element of $data, effectively taking the first element values of the sub arrays. array_map combines these results in a new array, keeping the original keys.
The second line does the same, but with the function end, which effectively grabs the last element's values of the sub-arrays.
The fact that both reset and end move the internal array pointer, is of no concern. The only thing that matters here is that they also return the value of the element where they put that pointer to.
Solution without loop and just for fun:
$result = [[], []];
$keys = array_keys($data);
array_map(function($item) use(&$result, &$keys) {
$key = array_shift($keys);
$result[0][$key] = $item[0];
$result[1][$key] = $item[1];
}, $data);
Just a normal foreach loop will do.
$item_1 = [];
$item_2 = [];
foreach ($data as $k => $v){
$item_1[$k] = $v[0];
$item_2[$k] = $v[1];
}
Hope this helps.
I have two arrays as shown below. I need to merge the content of the arrays so that I can get the structure as shown in the third array at last. I have checked array_merge but can't figure out the way this is possible. Any help appreciated. Thanks.
[
['gross_value' => '100', 'quantity' => '1'],
['gross_value' => '200', 'quantity' => '1']
]
and
[
['item_title_id' => '1', 'order_id' => '4'],
['item_title_id' => '2', 'order_id' => '4']
];
I should get a merged array like this:
[
[
'gross_value' => '100',
'quantity' => '1',
'item_title_id' => '1',
'order_id' => 4
],
[
'gross_value' => '200',
'quantity' => '1',
'item_title_id' => '2',
'order_id' => 4
]
]
Use array_merge_recursive :
Convert all numeric key to strings, (make is associative array)
$result = array_merge_recursive($ar1, $ar2);
print_r($result);
See live demo here
how about:
$arr1 = array(
0 => array(
'gross_value' => '100',
'quantity' => '1'
),
1 => array(
'gross_value' => '200',
'quantity' => '1'
)
);
$arr2 = array(
0 => array(
'item_title_id' => '1',
'order_id' => '4'
),
1 => array(
'item_title_id' => '2',
'order_id' => '4'
)
);
$arr = array();
foreach($arr1 as $k => $v) {
array_push($arr, array_merge($v, $arr2[$k]));
}
print_r($arr);
output:
Array
(
[0] => Array
(
[gross_value] => 100
[quantity] => 1
[item_title_id] => 1
[order_id] => 4
)
[1] => Array
(
[gross_value] => 200
[quantity] => 1
[item_title_id] => 2
[order_id] => 4
)
)
Have a look at array_merge
I would probably iterate over the arrays and merge them manually.
$result = array();
foreach ( $array1 as $key => $item )
{
$result[$key] = array_merge($array1[$key], $array2[$key]);
}
You will have an issue if the top-level arrays don't have strictly matching keys though.
If you have $array1 and $array2, try this:
foreach($array1 as $key1=>$innerArray){
$array1[$key1]['item_title_id'] = $array2[$key1]['item_title_id'];
$array1[$key1]['order_id'] = $array2[$key1]['order_id'];
}
The problem with things like merge recursive is that they don't know when to stop.
In some scenarios you want to stop traversing down an array and simply take a given value if it exists.
For instance if you have to override a nested config array you might not want the default keys to stick around at a a specific level.
here is my solution:
public static function merge_lvl2(){
$args = func_get_args();
return static::merge($args, 2);
}
public static function merge($args, $maxDepth = null, $depth = 1)
{
$merge = [];
foreach($args as $arg) {
if (is_array($arg)) {
if (is_array($merge)) {
if ($maxDepth == $depth) {
$arg += $merge;
$merge = $arg;
} else {
$merge = array_merge($merge, $arg);
}
} else {
$merge = $arg;
}
}
}
if ($maxDepth !== $depth) {
foreach($args as $a) {
if (is_array($a)) {
foreach($a as $k => $v) {
if (isset($merge[$k]) && is_array($merge[$k])) {
$merge[$k] = static::merge([$merge[$k], $v], $maxDepth, $depth + 1);
}
}
}
}
}
return $merge;
}
You can pass as many arrays to merge as you want to.
$merged = ClassName::merge_lvl2([..array1..], [..array2..], [..array3..], etc...);
It will stop merging at level 2 and accept the last instance of the key as an override instead of a merge.
You can also call merge directly with an array of args and setting the max depth.
If no max depth is set it will traverse the entire array.
The most modern, elegant, concise way to merge rows from two or more arrays (or the rows from a multidimensional array with 3 or more levels of depth) is to call array_merge() on each row (array_replace() can also be used). array_map() can call array_merge by its string name and the input data can be split into individual arguments with the "spread operator" (...) when needed.
Code for the OP's arrays: (Demo)
var_export(
array_map('array_merge', $arr1, $arr2)
);
The above technique will return a newly indexed array (though you might not notice because the sample input arrays were indexed to begin with). If your input data has associative first-level keys, they will be ignored and destroyed by this technique. If you have non-numeric first-level keys and want to merge on those, then array_merge_recursive() is likely to be the ideal native function - Demo.
However, it must be said, that for the OP's sample data array_merge_recursive() IS NOT a correct technique.
My first snippet is conveniently extended if you have more than two arrays which need their rows to be merge based on their positions. (Demo)
var_export(
array_map('array_merge', $arr1, $arr2, $arr3)
);
And as mentioned earlier, the spread operator can be used to unpack deeper arrays with the same result. Again, the number of subarrays containing rows can be dynamic. If your deep array only has one subarray containing rows, then the result will be a "flattening" effect where the top level is removed.
Code with new data structure: (Demo)
$masterArray = [
[
['gross_value' => '100', 'quantity' => '5'],
['gross_value' => '200', 'quantity' => '6']
],
[
['item_title_id' => '1', 'order_id' => '3'],
['item_title_id' => '2', 'order_id' => '4']
],
[
['foo' => 'bar1'],
['foo' => 'bar2']
]
];
var_export(
array_map('array_merge', ...$masterArray)
);
To be fair, array_replace_recursive() does provide the desired result using the OP's sample data, but I find the technique to be semantically misleading. (Demo)
All that said, you are not forced to use PHP's native array functions; you can use classic loops as well -- you will have several ways to "unite" the rows inside the loop. This approach is a little less D.R.Y. because you need to explicitly specific the separate arrays that you wish to synchronously iterate. Just make sure that you understand the nuanced differences in using array_merge(), array_replace(), and the union operator (+) with different qualities of data. Hint: associative, non-numeric keyed data in the respective rows will be affected when key collisions occur. Be careful to use a merging technique that will not overwrite the wrong data when rows share associative keys.
array_merge() to build a new array: (array_merge() Demo) (array_replace() Demo) (array union operator + Demo)
$result = [];
foreach ($arr1 as $i => $row) {
$result[] = array_merge($row, $arr2[$i]);
}
var_export($result);
Alternative, you can use the same general approach, but instead of populating a new $result array, you can merge data into the first array.
(array_merge() Demo) (array_replace() Demo) (array union assignment operator += Demo)
foreach ($arr1 as $i => &$row) {
$row = array_merge($row, $arr2[$i]);
}
var_export($arr1);
For the sake of completeness, if you have an indexed array of indexed arrays, then you might even use iterated calls of array_push() with the spread operator to achieve a similar functionality. This quite literally, indicatively appends the row data from subsequent arrays to the first array's rows.
Code: (Demo)
$arr1 = [
['A', 'B', 'C'],
['F', 'G']
];
$arr2 = [
['D', 'E'],
['H', 'I', 'J', 'L']
];
foreach ($arr1 as $i => &$row) {
array_push($row, ...$arr2[$i]);
}
var_export($arr1);
Related non-duplicate content on Stack Overflow:
Partially merge one array's row data with another another array:Add column of values from one array to another
Merge two flat arrays to create an array of merged rows:Transforming array values in elements of a subarray using PHP
Merge rows with indexed elements, remove duplicates and reindex:Merge two multidimensional arrays, preserve numeric keys, and combine values inside array
Merge arrays containing objects:Merge rows of two arrays containing objects by first level index
Push single elements from one array to rows in another array:Push elements from one array into rows of another array (one element per row)
On the above pages, the rabbit hole goes further because I've linked other related pages to them. Keep researching until you find what you need.
If you are using Laravel, you might be interested in its combine() and collect() methods.
Lets say I have an multidimensional string array:
.food = array(
'vegetable' => array(
'carrot' => 'blablue',
'potato' => 'bluebla',
'cauliflower' => 'blabla'
),
'Fruit' => array(
'apple' => 'chicken65',
'orange' => 'salsafood',
'pear' => 'lokkulakka'
)
);
is it possible to access the array by using index as numbers, instead of using the name of the key?
So for accessing chicken65 , I will type echo $food[1][0]; I don't want to use numbers as key, because its a big array and its more user-friendly if I use string as key and it will let me do for-loops on advanced level.
You can do foreach loops to achieve much the same thing as a typical for-loop.
foreach ($foods as $key => $value) {
//For the first iteration, $key will equal 'vegetable' and $value will be the array
}
$food[1][0] != $food[1]['apple'], so you cannot use numeric keys in this case.
try
$new_array = array_values($food);
however, variable can't start with .. It should start with $
you may want to try the function array_values but since you are dealing with multidemsional arrays, here is a solution posted by a php programmer
http://www.php.net/manual/en/function.array-values.php#103905
but it would be easier to use foreach instead of for.
You can use array_keys() on the array. The resulting array can be traversed via a for-loop and gives you the associative key.
I will show it to you for the first dimension:
$aTest = array('lol' => 'lolval', 'rofl' => 'roflval');
$aKeys = array_keys($aTest);
$iCnt = count($aKeys);
for($i = 0; $i < $iCnt; ++$i)
{
var_dump($aTest[$aKeys[$i]]);
}
You would need to do this for two dimensions but I would not recommend this. It is actually more obstrusive and slower than most other solutions.
I don't think there is something native to go this route.
And it does seem like you are trying to stretch array use a bit.
You should go OOP on this one.
Create a FoodFamilly object and a Food object in which you can store arrays if necessary and you'll be able to write a nice user-friendly code and add indices if needed.
OOP is almost always the answer :)