This question already has answers here:
Merge two flat indexed arrays of equal size so that values are pushed into the result in an alternating fashion
(2 answers)
Closed 6 months ago.
I have two arrays:
A = [1, 2, 3, 4]
B = ['a', 'b', 'c', 'd']
I want to merge them into tuples (A, B) in an one-dimensional array:
C = [1, 'a', 2, 'b', 3, 'c', 4, 'd']
Is there some native function in PHP that lets you interpolate two arrays this way? If not, would a loop be the most effective and eficient way to do this?
The number of elements of A will always be the same of B.
Note: If it helps, in the context of my specific needs, array A can be summarized as a single value (since the value will be the same for all values in B).
A = 1
B = ['a', 'b', 'c', 'd']
C = [1, 'a', 1, 'b', 1, 'c', 1, 'd']
Loops are OK in this case, since PHP does not have a native function to interleave 2 arrays, but this is a nice way to solve the problem:
function interleave($array1, $array2) {
$result = array();
array_map(function ($e1, $e2) use (&$result) {
array_push($result, $e1, $e2);
}, $array1, $array2);
return $result;
}
I don't know if there is any built-in mapping function that makes this easier, but this is a simple, naive implementation.
$a = array(1,2,3,4);
$b = array('a','b','c','d');
function array_interpolate($a, $b) {
if (sizeof($a) != sizeof($b))
throw new Exception('Arrays must be of same size');
$result = array();
for ($i = 0, $l = sizeof($a); $i < $l; $i++) {
$result[2*$i] = $a[$i];
$result[2*$i+1] = $b[$i];
}
return $result;
}
$res = array_interpolate($a, $b);
print_r($res);
The above returns
Array
(
[0] => 1
[1] => a
[2] => 2
[3] => b
[4] => 3
[5] => c
[6] => 4
[7] => d
)
$C = call_user_func_array('array_merge', call_user_func_array('array_map', array(NULL, $A, $B)));
Since in PHP arrays are implemented as hash tables (Hash table on wikipedia), you won't be able to achieve your goal faster then looping through array.
Here is a simplest example:
function interpolate(array $a,array $b) {
$result = array();
for($i = 0; $i < count($a); $i++) {
$result[] = $a[$i];
$result[] = $b[$i];
}
return $result;
}
Related
I have two arrays, $array_A and $array_B. I'd like to append the first value from $array_B to the end of the first value of $array_A and repeat this approach for all elements in both arrays.
$array_A = ['foo', 'bar', 'quuz'];
$array_B = ['baz', 'qux', 'corge'];
Expected output after squishing:
['foobaz', 'barqux', 'quuzcorge']
array_merge($array_A, $array_B) simply appends array B onto array A, and array_combine($array_A, $array_B) sets array A to be the key for array B, neither of which I want. array_map seems pretty close to what I want, but seems to always add a space between the two, which I don't want.
It would be ideal for the lengths of each array it to be irrelevant (e.g. array A has five entries, array B has seven entries, extra entries are ignored/trimmed) but not required.
// updated version
$a = ['a', 'b', 'c'];
$b = ['d', 'e', 'f', 'g'];
print_r(array_map('implode', array_map(null, $a, $b)));
Probably the fastest code, but more verbose than other options.
//updated version
$array_A = ['foo', 'bar', 'quuz'];
$array_B = ['baz', 'qux', 'corge'];
for ($i = 0, $c = count($array_A); $i<$c; $i++) {
$result[$i] = $array_A[$i].$array_B[$i];
}
var_dump($result);
There isn't an array function in PHP that does exactly that. However, you can write one yourself, like this one:
function array_zip($a1, $a2) {
$out = [];
for($i = 0; $i < min(sizeof($a1), sizeof($a2)); $i++) {
array_push($out, $a1[$i] . $a2[$i]);
}
return $out;
}
So given these arrays and running it:
$a = ["foo", "bar"];
$b = ["baz", "qux"];
print_r(array_zip($a, $b));
You would get:
Array
(
[0] => foobaz
[1] => barqux
)
Try this:
$A = ['foo', 'bar'];
$B = ['baz', 'qux'];
function arraySquish($array)
{
$new = [''];
foreach($array as $val) {
$new[0] .= $val;
}
return $new;
}
$A = arraySquish($A);
$B = arraySquish($B);
echo '<pre>';
print_r($A);
print_r($B);
echo '</pre>';
PHP Fiddle here.
An explicit array_map:
<?php
$colours = ['red', 'white', 'blue'];
$items = ['robin', 'cloud', 'mountain'];
$squished =
array_map(
function($colour, $item) {
return $colour.$item;
},
$colours,
$items
);
var_export($squished);
Output:
array (
0 => 'redrobin',
1 => 'whitecloud',
2 => 'bluemountain',
)
If you want to only go as far as the smallest array, you could either return null if either entries are null, and then filter your result.
Or truncate the arrays to the same length:
$b = array_intersect_key($b, $a);
$a = array_intersect_key($a, $b);
Regardless of if both arrays have the same length or if one is longer than the other or in what order the arrays occur in, the following technique will "squish" the values into a flat array of strings.
array_map() only needs to be called once and implode()'s default "glue" string is an empty string -- so it can be omitted.
Code: (Demo)
$a = ['a', 'b', 'c'];
$b = ['d', 'e', 'f', 'g'];
var_export(array_map(fn() => implode(func_get_args()), $a, $b));
Or consolidate the column data with spread operator: (Demo)
var_export(array_map(fn(...$column) => implode($column), $a, $b));
Output:
array (
0 => 'ad',
1 => 'be',
2 => 'cf',
3 => 'g',
)
It is hard to explain, but i will try my best.
In html, got a row of item A B C D E. They are not in array.
Now got another array which is Num[]={1,2,3,4,5,6,7,8,9}.
Imagine A=1, B=2, C=3, D=4, E=5, 0=6, 0=7, 0=8, 0=9.
Now, i use checkbox to check the item B,C,E and form an array check[]={B,C,E}.
Question is: How to know that the new array check[0]=2, check[1]=3, check[2]=5?
Sorry, i cant explain well, for me its complicated.(no code provided because its too long)
Using array_intersect() which matches the two arrays up (the first one and the one with the values you want to find) gives you an array with just those items and the keys from the first array. You can then use array_intersect_key() which extracts the items from the second array with the keys extracted in the first step.
$a1 = ['A', 'B', 'C', 'D', 'E'];
$a2 = [1,2,3,4,5];
$a3 = ['A', 'D'];
$a4 = array_intersect_key($a2, array_intersect($a1, $a3));
print_r($a4);
which outputs...
Array
(
[0] => 1
[3] => 4
)
You can use array_values() if you want the keys to be sequential.
$a4 = array_values(array_intersect_key($a2, array_intersect($a1, $a3)));
Try with array_map
$abc = array('A', 'B', 'C', 'D', 'E');
$num = array(1, 2, 3, 4, 5);
$newAbc = array('A', 'D');
$newNum = array_map(function($element) use($abc, $num) {
return $num[array_search($element, $abc)];
}, $newAbc);
// Outputs: 1, 4
print_r($newNum);
The array_intersect solution is very clean too :)
A simple solution would be a map, which maps the content ABC to Num.
$abc = ['A', 'B', 'C', 'D', 'E'];
$num = [1, 2, 3, 4, 5];
$map = [];
foreach ($abc as $index => $val) {
$map[$val] = $num[$index];
}
$x = ['A', 'D'];
foreach ($x as $index => $val) {
echo "x[$index] = {$map[$val]}\n";
}
If you have to do this only for one element, you could also skip the map creation part and use array_search;
echo $num[array_search('A', $abc)];
<?php
$chars = ['A', 'B' , 'C' , 'D' , 'E'];
$ints = [ 1 , 2 , 3 , 4 , 5];
$given = ['A', 'D'];
$require = [1, 4];
Combine and intersect:
$ints_chars = array_combine($ints, $chars);
var_export($ints_chars);
$result = array_keys(array_intersect($ints_chars, $given));
var_dump($result === $require);
Output:
array (
1 => 'A',
2 => 'B',
3 => 'C',
4 => 'D',
5 => 'E',
)bool(true)
Use a map:
$result = [];
$chars_ints = array_combine($chars, $ints);
foreach($given as $char)
$result[] = $chars_ints[$char];
var_dump($result === $require);
Output:
bool(true)
Use a map, but notice your number range is just a shifted index:
$result = [];
$chars_flip = array_flip($chars);
foreach($given as $char)
$result[] = $chars_flip[$char] + 1;
var_dump($result === $require);
Output:
bool(true)
Finally by shifting and mutating the original array:
array_unshift($chars, null);
$result = array_keys(array_intersect($chars, $given));
var_dump($result === $require);
Output:
bool(true)
i have two arrays like
$a1 $b1
0 : A 10
1: B 10
2: A 15
3: A 20
4: B 05
5: c 25
now i want to calculate them in same way then result is A=45, B=15 and C=25
$calc = array_fill_keys($a1,0);
foreach($a1 as $i => $key) {
$calc[$key] += $b1[$i];
}
$calc is array of calculated values:
[A] => 45,
[B] => 15
etc.
I know it's already been answered and accepted, and the accepted answer is a lot simpler and more efficient; but purely because I was tempted to try a rather different approach:
$a1 = array('A', 'B', 'A', 'A', 'B', 'c');
$b1 = array('10','10','15','20','05','25');
$sumArray = array();
foreach(array_unique($a1) as $key) {
$arrayElements = array_filter(
$a1,
function($value) use ($key) {
return $value == $key;
}
);
$sumArray[$key] = array_sum(
array_intersect_key(
$b1,
array_fill_keys(
array_keys($arrayElements),
NULL
)
)
);
}
var_dump($sumArray);
I have values in some array I want to re index the whole array such that the the first value key should be 1 instead of zero i.e.
By default in PHP the array key starts from 0. i.e. 0 => a, 1=> b, I want to reindex the whole array to start from key = 1 i.e 1=> a, 2=> b, ....
$alphabet = array("a", "b", "c");
array_unshift($alphabet, "phoney");
unset($alphabet[0]);
Edit: I decided to benchmark this solution vs. others posed in this topic. Here's the very simple code I used:
$start = microtime(1);
for ($a = 0; $a < 1000; ++$a) {
$alphabet = array("a", "b", "c");
array_unshift($alphabet, "phoney");
unset($alphabet[0]);
}
echo (microtime(1) - $start) . "\n";
$start = microtime(1);
for ($a = 0; $a < 1000; ++$a) {
$stack = array('a', 'b', 'c');
$i= 1;
$stack2 = array();
foreach($stack as $value){
$stack2[$i] = $value;
$i++;
}
$stack = $stack2;
}
echo (microtime(1) - $start) . "\n";
$start = microtime(1);
for ($a = 0; $a < 1000; ++$a) {
$array = array('a','b','c');
$array = array_combine(
array_map(function($a){
return $a + 1;
}, array_keys($array)),
array_values($array)
);
}
echo (microtime(1) - $start) . "\n";
And the output:
0.0018711090087891
0.0021598339080811
0.0075368881225586
Here is my suggestion:
<?php
$alphabet = array(1 => 'a', 'b', 'c', 'd');
echo '<pre>';
print_r($alphabet);
echo '</pre>';
?>
The above example will output:
Array
(
[1] => a
[2] => b
[3] => c
[4] => d
)
Simply try this
$array = array("a","b","c");
array_unshift($array,"");
unset($array[0]);
Ricardo Miguel's solution works best when you're defining your array and want the first key to be 1. But if your array is already defined or gets put together elsewhere (different function or a loop) you can alter it like this:
$array = array('a', 'b', 'c'); // defined elsewhere
$array = array_filter(array_merge(array(0), $array));
array_merge will put an array containing 1 empty element and the other array together, re-indexes it, array_filter will then remove the empty array elements ($array[0]), making it start at 1.
$array = array('a', 'b', 'c', 'd');
$array = array_combine(range(1, count($array)), array_values($array));
print_r($array);
the result:
Array
(
[1] => a
[2] => b
[3] => c
[4] => d
)
If you are using a range, try this code:
$data = array_slice(range(0,12), 1, null, true);
// Array ( [1] => 1 [2] => 2 [3] => 3 [4] => 4 [5] => 5 [6] => 6 [7] => 7 [8] => 8 [9] => 9 [10] => 10 [11] => 11 [12] => 12 )
I see this answer is very old, but my solution for this is by adding a +1 to your index. I'll do that because I think this is much faster and easy to read. When you print this it will start from 1 because 0+1 =1, then 2 etc.
foreach($items as $index => $item){
echo $index+1 . $item
}
I think it is simple as that:
$x = array("a","b","c");
$y =array_combine(range(1, count($x)), $x);
print_r($y);
$data = ['a', 'b', 'c', 'd'];
$data = array_merge([''], $data);
unset($data[0]);
I have found that this will perform slightly better, than the accepted solution, on versions of PHP 7.1+.
Benchmark code:
$start = microtime(1);
for ($a = 0; $a < 10000; ++$a) {
$data = ['a', 'b', 'c', 'd'];
$data = array_merge([''], $data);
unset($data[0]);
}
echo (microtime(1) - $start) . "\n";
$start = microtime(1);
for ($a = 0; $a < 10000; ++$a) {
$data = ['a', 'b', 'c', 'd'];
array_unshift($data, '');
unset($data[0]);
}
echo (microtime(1) - $start) . "\n";
Scripts execution time (PHP 7.4):
0.0011248588562012
0.0017051696777344
And the difference of these benchmarks will increase as the number of array values increases.
If you already have an array and want to reindex it
to start from index X instead of 0, 1, 3...N then:
// Check if an array is filled by doing this check.
if (count($your_array) > 0) {
// Let's say we want to start from index - 5.
$your_array = [5 => $your_array[0], ...array_slice($your_array, 1)];
}
About spread operator "..."
https://www.php.net/manual/en/migration56.new-features.php#migration56.new-features.splat
P.S.
Real-world scenario/use-case, what I've met in work doing a task for a client:
I had one <div> that contains two <tables>. Each <table> contains markup for the days of the week. The first one has days from Monday to Thursday. The second one has days from Friday to Sunday. So, in my task, I had the variable represent a week in which each day had hours of open and close. I needed appropriately divide that week's variable into two.
<table>
<?php for ($dayIndex = 0; $dayIndex < 4; $dayIndex++): ?>
<?php
$_timetable = array_slice($timetable, 0, 4);
// $renderTimetableRow is an anonymous function
// that contains a markup to be rendered, like
// a html-component.
$renderTimetableRow($_timetable, $dayIndex);
?>
<?php endfor; ?>
</table>
<table>
<?php for($dayIndex = 4; $dayIndex < 7; $dayIndex++): ?>
<?php
if (count($_timetable = array_slice($timetable, 4, 7)) > 0) {
$_timetable = [4 => $_timetable[0], ...array_slice($_timetable, 1)];
}
// $renderTimetableRow is an anonymous function
// that contains a markup to be rendered, like
// a html-component.
$renderTimetableRow($_timetable, $dayIndex);
?>
<?php endfor; ?>
</table>
try this
<?php
$stack = array('a', 'b', 'c', 'd');
$i= 1;
foreach($stack as $value){
$stack2[$i] = $value;
$i++;
}
$stack = stack2;
?>
$a = array(0=>'a',1=>'b',2=>'c', 3=>'d');
I want to change the order to be 3,2,0,1:
$a = array(3=>'d',2=>'c',0=>'a', 1=>'b');
If you want to change the order programmatically, have a look at the various array sorting functions in PHP, especially
uasort()— Sort an array with a user-defined comparison function and maintain index association
uksort()— Sort an array by keys using a user-defined comparison function
usort()— Sort an array by values using a user-defined comparison function
Based on Yannicks example below, you could do it this way:
$a = array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd');
$b = array(3, 2, 0, 1); // rule indicating new key order
$c = array();
foreach($b as $index) {
$c[$index] = $a[$index];
}
print_r($c);
would give
Array([3] => d [2] => c [0] => a [1] => b)
But like I said in the comments, if you do not tell us the rule by which to order the array or be more specific about your need, we cannot help you beyond this.
Since arrays in PHP are actually ordered maps, I am unsure if the order of the items is preserved when enumerating.
If you simply want to enumerate them in a specific order:
$a = array(0=>'a',1=>'b',2=>'c', 3=>'d');
$order = array(3, 2, 0, 1);
foreach ($order as $index)
{
echo "$index => " . $a[$index] . "\n";
}
function reorder_array(&$array, $new_order) {
$inverted = array_flip($new_order);
uksort($array, function($a, $b) use ($inverted) {
return $inverted[$a] > $inverted[$b];
});
}
$a = array(0=>'a',1=>'b',2=>'c', 3=>'d');
reorder_array($a, array(3, 2, 0, 1));
var_dump($a);
Result:
Array ( [3] => d [2] => c [0] => a [1] => b )
The easiest way to do it with uksort(), more functional way:
$a = ['a','b','c','d'];
$order = [3, 2, 0, 1];
uksort($a, function($x, $y) use ($order) {
return array_search($x, $order) > array_search($y, $order);
});
print_r($a); // [3 → d, 2 → c, 0 → a, 1 → b]
A more general aproach:
$ex_count = count($ex_names_rev_order);
$j = 0;
$ex_good_order = array();
for ($i=($ex_count - 1); $i >= 0 ; $i--) {
$ex_good_order[$j] = $ex_names_rev_order[$i];
$j++;
}