I need to add the values of an associative array to another one.
$a = array(4=>2,5=>5);
$b = arrray(array(0=>0,1=>4,2=>10,3=>1000),array()...);
What I'm expecting to get is a third array ($c) like the one below where the content of $b follows the content of $a:
$c = array(array(4=>2,5=>5,0=>0,1=>4,2=>10,3=>1000),array(4=>2,5=>5....));
This is what I've written (not working):
$c = array();
foreach ($possible_opp_action as $sub) {
$c[] = array_push($to_merge,array_values($sub));
}
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),
array(0=>0,1=>40,2=>100,3=>2000),
array(4=>10)
);
$c = array();
foreach($b as $tmp) {
$c[] = $a+$tmp;
}
var_dump($c);
Unlike array_merge, this will maintain numeric keys... but watch out for duplicate keys
$c = array();
foreach ($b as $bb) {
$c[] = array_merge($a,$bb);
}
If you do not need $b in original form:
<?php
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),array());
foreach ($b as &$ref) {
$ref = $a + $ref;
}
var_dump($b);
Otherwise:
<?php
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),array());
$c = array();
foreach ($b as &$ref) {
$c[] = $a + $ref;
}
var_dump($c);
You need array_merge.
http://us.php.net/manual/en/function.array-merge.php
Note the handling of duplicate keys:
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
EDIT:
I may have not read the question right - please clarify...
Do you want all the array items in a single array, or an array with the original arrays as items in it (an array of arrays)?
IE:
c = array(a=a, b=b, c=c, etc.) <- can be done with array_merge($a, $b, $c, etc)
vs
c = array(
b = array(a=a, b=b, c=c, etc),
a=array(d=d, e=e, etc.)
) <- should be done by just concatenating the next array on the end like this (and skip the $c altogether):
$c[] = $b;
$c[] = $a;
//or
$c = array();
foreach ($possible_opp_action as $sub) {
$c[] = $sub;
}
try
$c = array_merge($b, $a)
help in http://php.net/manual/es/function.array-merge.php
Related
I have an array for example
$a = [1,2,3,4,5];
From this $a, how to take last one and set it first like [5,1,2,3,4]
And how do I take last two arrays to make it like [4,5,1,2,3]
You can combine using array_pop(), which pops the last element of the array out, and array_unshift() to push it to the front of the array. You can create a simple function for this,
function array_pop_unshift($array) {
array_unshift($array, array_pop($array));
return $array;
}
Then use it as
$a = [1,2,3,4,5];
$new = array_pop_unshift($a);
print_r($new); // [5,1,2,3,4]
To continue shifting it, just call the function again until you're done, for instance through a for loop,
$a = [1,2,3,4,5];
for ($i = 0; $i < 2; $i++) {
$new = array_pop_unshift($a);
}
print_r($new); // [4,5,1,2,3]
Live demo at https://3v4l.org/CoJZZ
If you want to avoid the cost of several array_unshift and array_pop, you can build a generator that plays with the array internal pointer.
If you really need a result array, use iterator_to_array() to create it:
$a = range(1,5);
function rotate(&$array, $step = 1) {
$length = count($array);
end($array);
while ($step--)
prev($array);
while ($length--) {
next($array);
if (key($array) === null)
reset($array);
yield current($array);
}
}
print_r(iterator_to_array(rotate($a, 2))); // [4,5,1,2,3]
demo
Note that the rotate() generator uses a reference to avoid the array copy but doesn't modify the orginal array: it only moves the array pointer n times (where n is the array length) from the choosen position. When the array pointer is out of the array (key() returns null) the array pointer is reseted. In other words it stays efficient even with a large array and many rotations (what I have called "step" in the code).
You are actually doing right rotation, not left. Anyway, here are functions for doing both of them. They are probably not the most efficient but they are short in code and pretty self-explanatory:
<?php
function rotateLeft($array, $times) {
for($i=0; $i<$times; $i++){
$array[] = array_shift($array);
}
return $array;
}
function rotateRight($array, $times) {
for($i=0; $i<$times; $i++){
array_unshift($array, array_pop($array));
}
return $array;
}
$a = [1,2,3,4,5];
$a = rotateRight($a, 1);
print_r($a);
?>
to take last one and set it first This is known as right rotation.
And
$k is the number of units the shifting should be. $a is the array.
for($x=0; $x < $k; $x++){
//remove last element
$last = array_pop($a);
//push last element to the beginning
array_unshift($a, $last);
}
array_pop() pops and returns the value of the last element of array, shortening the array by one element.
https://www.php.net/manual/en/function.array-pop.php
array_unshift() prepends passed elements to the front of the array
https://www.php.net/manual/en/function.array-unshift.php
You could create a function that takes two arguments $k(number of rotations), $a (the array) and returns the array after performing right rotation $k times.
function rotateRight($a, $k){
for($x=0; $x < $k; $x++){
//remove last element
$last = array_pop($a);
//push last element to the beginning
array_unshift($a, $last);
}
return $a;
}
And then call it accordingly.
Example:
$a = [1,2,3,4,5];
$a_one_shift = rotateRight($a, 1);
// [5,1,2,3,4];
$a_two_shift = rotateRight($a_one_shift, 1);
// [4,5,1,2,3];
Or you could pass 2 to directly get the array after two right rotations.
$a_new = rotateRight($a, 2);
// [4,5,1,2,3];
Rather than making iterated calls of array_pop() and array_unshift(), use an efficient, elegant approach that makes fewer function calls and has the lowest possible time complexity. Using early returns prevents making needless function calls for the same result.
Code: (Demo)
function popUnshift(array $indexedArray, int $popShiftsCount): array
{
$count = count($indexedArray);
if ($count < 2) {
return $indexedArray; // array cannot be rotated
}
$remainder = $popShiftsCount % $count;
if (!$remainder) {
return $indexedArray; // sought rotation is the original order
}
return array_merge(
array_splice($indexedArray, -$remainder),
$indexedArray
);
}
Disclosure: This answer was built on the CodeReview page (Codility cyclic rotation solution in PHP) where I offered this snippet in my review.
//$A input array, $K rotation times
function solution($A, $K) {
$new = array();
for($j=1;$j<=$K;$j++)
{
if(count($new)>0)
$A = $new;
for($i=0;$i<count($A);$i++)
{
if($i==0)
$new[$i] = $A[count($A)-1];
else
$new[$i] = $A[$i-1];
}
}
return $new;}
For example, input array is [9,1,9,1,3,9,1,2,9] output array will be [9,9,9,9,1,1,1,2,3].
Here's what I've tried below but not giving me expected result:
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
$popular = array_keys($values);
print_r(array_values($popular));
foreach ($values as $key => $val) {
echo $key.", ";
}
Output:
Array
(
[0] => 9
[1] => 1
[2] => 3
[3] => 2
)
9, 1, 3, 2,
If we loop the array_count_values then we can make sure they come in the correct order.
When there is two that is the same count I find all the same with array_intersect then foreach them and add in the correct order.
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
//var_dump($values);
$result =[];
$same = [];
foreach($values as $key => $val){
if(!in_array($key, array_keys($same))){
if(next($values) != $val){
$result = array_merge($result, array_fill(0, $val, $key));
}else{
$same = array_intersect($values, [$val]);
ksort($same);
foreach($same as $skey => $val){
$result = array_merge($result, array_fill(0, $val, $skey));
}
//var_dump($same);
}
}
}
var_dump($result);
https://3v4l.org/sk44Q
Try usort combined with array_count (php >= 7.0):
$array = [9,1,9,1,3,9,1,2,9];
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
$countA = $arrayCounts[$a] ?? 0;
$countB = $arrayCounts[$b] ?? 0;
if ($countA == $countB) {
return $a == $b ? 0 : ($a < $b ? -1 : 1);
}
return ($countA > $countB) ? -1 : 1;
});
You could use this sequence:
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
return $arrayCounts[$b] - $arrayCounts[$a] ?: $a - $b;
});
Now $array is sorted as requested.
The callback function that is passed as argument to usort should return a negative number when the two elements $a and $b should stay in that order (from left to right), or a positive number when they should be reversed. 0 when it does not matter.
The numeric expression that is returned in this particular callback function subtracts the frequencies of $a and $b. If $b occurs more, then that subtraction is positive, and that is returned. Similarly if the subtraction is negative, then that negative value is returned. Now when the frequencies are equal, the ?: operator kicks in and the expression after it is evaluated. That other subtraction also results in a positive or negative value, based on the original value itself. So $a - $b will be negative when $a < $b, which means the order can remain as it is (knowing that we already derived that their frequencies were equal).
How to combine strings $a and $b so that 1st digit of $a is placed as 2nd character of $b, 2nd digit as 4th character of $b, 3rd digit as 7th character of $b and 4th digit as 11th character of $b.
So lets say $a = 1234
and $b = abcdefghijklmnop
I want to get this: a1b2cd3efg4hijklmnop
Is there a function to combine it like this + reverse back if needed?
You could do this using multiple array and using array_splice() to insert the value at a certain point.
$logicArr = [1,3,6,10]; //Logic Array = Each position of array
$arrOne = [1,2,3,4]; //Values to add to the array
$arrTwo = ['a','b','c','d','e','f','g', 'h','i','j','k','l','m','n','o','p']; //Data Array
foreach ($arrOne as $k=>$v) {
array_splice($arrTwo, $logicArr[$k], 0, $v); //Insert value from $arrOne at position $logicArr[$k] using iteration of Foreach loop.
}
You could iterate through each character in $b and only insert the next character from $a whenever you reach the desired position:
function mix($a, $b)
{
$a = str_split($a);
$b = str_split($b);
$mixed = '';
$nextInsertPos = 1; // 2nd character
$indexA = 0;
foreach ($b as $indexB => $charB) {
if ($indexB + $indexA == $nextInsertPos) {
$mixed .= $a[$indexA++];
$nextInsertPos = $nextInsertPos + ($indexA + 1);
}
$mixed .= $charB;
}
return $mixed;
}
I have :
$a = array(
0=>'you',
1=>'will',
2=>'be',
3=>'so',
4=>'happy',
5=>'in'
);
$b = array(
0=>'1',
1=>'4',
2=>'5'
); // (KEYS:1,4,5)
I want out the values of $a that matches $b's keys;
so $val would be willhappyin.
And then comma-separate them.. like: will,happy,in without comma after last one.
How can i do this ? :)
$string = implode(",", array_intersect_key($a, array_flip($b)));
EXPLANATION:
array_flip switches the values of $b to keys.
array_intersect_key takes only the entries in $a that are also present in $b.
implode joins the resulting array values together by comma.
$c = array();
foreach($b as $key)
{
$c[] = $a[$key]
}
echo implode(",",$c);
$out_arr = array();
foreach ($b as $k => $v) {
array_push($out_arr, $a[$v]);
}
return join($out_arr, ',');
I need to combine two foreach statement into one for example
foreach ($categories_stack as $category)
foreach ($page_name as $value)
I need to add these into the same foreach statement
Is this possible if so how?
(I am not sure I have understood your question completely. I am assuming that you want to iterate through the two lists in parallel)
You can do it using for loop as follows :
$n = min(count($category), count($value));
for($c = 0; $c < $n; $c = $c + 1){
$categories_stack = $category[$c];
$pagename = $value[$c];
...
}
To achieve the same with foreach you need a function similar to Python's zip() function.
In Python, it would be :
for categories_stack, pagename in zip(categories, values):
print categories_stack, pagename
Since PHP doesn't have a standard zip() function, you'll have to write such a function on your own or go with the for loop solution.
You can do nested foreachs if that's what you want. But without knowing more of your data, it's impossible to say if this helps:
foreach ($categories_stack as $category) {
foreach ($page_name as $value) {
}
}
Probably you want to print out all pages in a category? That probably won't work, so can you give a bit more info on how the arrays look like and relate to each other?
This loop will continue to the length of the longest array and return null for where there are no matching elements in either of the arrays. Try it out!
$a = array(1 => "a",25 => "b", 10 => "c",99=>"d");
$b = array(15=>1,5=>2,6=>3);
$ao = new ArrayObject($a);
$bo = new ArrayObject($b);
$ai = $ao->getIterator();
$bi = $bo->getIterator();
for (
$ai->rewind(),$bi->rewind(),$av = $ai->current(),$bv = $bi->current();
list($av,$bv) =
array(
($ai->valid() ? $ai->current() : null),
($bi->valid() ? $bi->current() : null)
),
($ai->valid() || $bi->valid());
($ai->valid() ? $ai->next() : null),($bi->valid() ? $bi->next() : null))
{
echo "\$av = $av\n";
echo "\$bv = $bv\n";
}
I cannot really tell from the question exactly how you want to traverse the two arrays. For a nested foreach you simply write
foreach ($myArray as $k => $v) {
foreach ($mySecondArray as $kb => $vb {
}
}
However you can do all sorts of things with some creative use of callback functions. In this case an anonymous function returning two items from each array on each iteration. It's then easy to use the iteration value as an array or split it into variables using list() as done below.
This also has the added benefit of working regardless of key structure. I's purely based on the ordering of array elements. Just use the appropriate sorting function if the elements are out of order.
It does not worry about the length of the arrays as there is no error reported, so make sure you keep an eye out for empty values.
$a = array("a","b","c");
$b = array(1,2,3);
foreach (
array_map(
create_function(
'$a,$b', 'return array($a,$b);'
)
,$a,$b
)
as $value
)
{
list($a,$b) = $value;
echo "\$a = $a\n";
echo "\$b = $b\n";
}
Output
$a = a
$b = 1
$a = b
$b = 2
$a = c
$b = 3
Here's another one for you that stops on either of the lists ending. Same as using min(count(a),count(b). Useful if you have arrays of same length. If someone can make it continue to the max(count(a),count(b)) let me know.
$ao = new ArrayObject($a);
$bo = new ArrayObject($b);
$ai = $ao->getIterator();
$bi = $bo->getIterator();
for (
$ai->rewind(),$bi->rewind();
$av = $ai->current(),$bv=$bi->current();
$ai->next(),$bi->next())
{
echo "\$av = $av\n";
echo "\$bv = $bv\n";
}
This is where the venerable for loop comes in handy:
for(
$i = 0,
$n = sizeof($categories_stack),
$m = sizeof($page_name);
$i < $n && $i < $m;
$i++
) {
$category = $categories_stack[$i];
$value = $page_name[$i];
// do stuff here ....
}
Surely you can just merge the arrays before looping?
$data = array_merge($categories_stack, $page_name);
foreach($data AS $item){
...
}
Do the array elements have a direct correspondence with one another, i.e. is there an element in $page_name for each element in $categories_stack? If so, just iterate over the keys and values (assuming they have the same keys):
foreach ($categories_stack as $key => $value)
{
$category = $value;
$page = $page_name[$key];
// ...
}
Could you just nest them with variables outside the scope of the foreach, or prehaps store the content as an array similar to a KVP setup? My answer is vague but I'm not really sure why you're trying to accomplish this.