Merge arrays with control of array position - php

I have two random arrays merged, everything displaying/functioning beautifully. The one stuck I have is this:
When I merge the two arrays together I need to make sure that every 3 item comes from array2.
array1 (a,b,c,d,e,f,g,h,i,j,k)
array2 (a1,a2,a3,a4)
My desired outcome:
d k c a1 j i g a2 etc.
What I have done so far:
function randomize_blocks($arr, $num = 1) {
shuffle($arr);
$r = array();
for ($i = 0; $i < $num; $i++) {
$r[] = $arr[$i];
}
return $num == 1 ? $r[0] : $r;
}
//gather donor blocks into an array
$donorBlocks = array($blockA, $blockB, $blockC, $blockD, $blockE, $blockF,
$blockG, $blockH, $blockI, $blockJ, $blockK, $blockL, $blockM, $blockN,
$blockO);
//gather value blocks into an array
$valueBlocks = array($valueA, $valueB, $valueC, $valueD);
//shake that shuffler real hard! DT
$shuffled_valueBlocks = randomize_blocks($valueBlocks, 4);
$shuffled_donorBlocks = randomize_blocks($donorBlocks, 15);
//combine our shuffled arrays together
$combinedArrays = array_merge($shuffled_valueBlocks, $shuffled_donorBlocks);
//shuffle them all together!
$shuffled_blocks = randomize_blocks($combinedArrays, 19);
//display bocks on page
foreach ($combinedArrays as $key => $value) {
echo $value;
}
What is the best way to accomplish this?

Here is a way with array_splice to modify the longest of the two arrays into the desired result:
$a = ['a', 'b', 'c', 'd'];
$b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
foreach ($a as $i => $v)
array_splice($b, $i*4+3, 0, [$v]);
$b will be:
[1, 2, 3, 'a', 4, 5, 6, 'b', 7, 8, 9, 'c', 10, 11, 12, 'd', 13, 14, 15]

What about something like this?
$a1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'];
$a2 = ['a1', 'a2', 'a3', 'a4'];
$a = [];
shuffle($a1);
foreach ($a1 as $k => $v) {
$a[] = $v;
if (($k + 1) % 3 === 0 && $a2) $a[] = array_shift($a2);
}

This is based on the assumption that you want both arrays shuffled as well as placed in your desired pattern:
$array_one = array('a','b','c','d','e','f','g','h','i','j','k');
$array_two = array('a1','a2','a3','a4');
function merge_random_interval($array_one = array(), $array_two = array(), $interval = 3) {
$return_array = array();
// Shuffle the arrays - that seems to be important?
shuffle($array_one);
shuffle($array_two);
// Go through the first array
$array_two_index = 0;
for ($i = 0; $i < count($array_one); $i++) {
// Every $interval add a value from the second array
if ($i > 0 && $i % $interval == 0) {
// Make sure there is a value in the second array
if (isset($array_two[$array_two_index])) {
$return_array[] = $array_two[$array_two_index];
$array_two_index++;
}
}
$return_array[] = $array_one[$i];
}
// You may want to check if $array_two has more values that weren't added?
// Compare $array_two_index against count($array_two)
return $return_array;
}
$result_array = merge_random_interval($array_one, $array_two, 3);
echo implode(' ', $result_array); // g d c a1 h i j a4 b e a a2 k f

Related

Given two arrays combine common values

$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
The indexes of $names and $money correspond to each other.
I need to find the most efficient way to add common $money to each $names and print only the even values.
For example, john appears two times, with 2 and 3 money. So johnhas 5 money.
Desired output:
mark: 20
brian: 8
paul: 6
I am thinking of looping through each array, but this is O(n^2) Is there an easier way?
Make associative array (hash) for result:
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$result = [];
for ($i = 0; $i < count($names); $i++) {
if (!isset($result[$names[$i]])) {
$result[$names[$i]] = 0;
}
$result[$names[$i]] += $money[$i];
}
arsort($result); // reverse (big first) sort by money
print_r($result);
just loop through names and use it keys for money array:
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$res = [];
foreach ($names as $key => $value) {
$res[$value] = isset($res[$value]) ? $res[$value] + $money[$key] : $money[$key];
}
var_dump($res);
You just have to loop through $names once and set name as key in a result- variable.
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$data = [];
foreach ($names as $key => $name) {
if (!isset($data[$name])) {
$data[$name] = 0;
}
$data[$name] += $money[$key];
}
print_r($data);
Maybe you'll need a check, if both arrays have the same size.
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$result = [];
foreach ($names as $index => $name) {
if (empty($result[$name]) {
$result[$name] = $money[$index];
} else {
$result[$name] += $money[$index];
}
}
print_r($result);

How to Match new Array with original array

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)

Create pairs with 2 array, so that there is no repeated pairs?

I'm trying to create a script to create pairs from 2 different arrays. For example I have two array given below:
<?php
//Array 1
$arr1 = array('A', 'B', 'C', 'D');
//Array 2
$arr2 = array('X', 'Y', 'Z');
And I need output in such a manner so that it match with each element and didn't repeat pair and sequence also. Here is expected output:
$output = array(
0 => array('A', 'X'),
1 => array('B', 'Y'),
2 => array('C', 'Z'),
3 => array('D', 'X'),
4 => array('A', 'Y'),
5 => array('B', 'Z'),
6 => array('C', 'X'),
7 => array('D', 'Y'),
8 => array('A', 'Z'),
9 => array('B', 'X'),
10 => array('C', 'Y'),
11 => array('D', 'Z')
)
**Note: 2 arrays can differ with number of count and values.
This is Cartesian Product. Could be achieved with
//Array 1
$arr1 = array('A', 'B', 'C', 'D');
//Array 2
$arr2 = array('X', 'Y', 'Z');
$output = array();
foreach($arr1 as $i1){
foreach ($arr2 as $i2) {
$output[] = array($i1, $i2);
}
}
echo json_encode($output);
If you want the output to be in the same order as you have mentioned above, following should do that.
$newoutput = array();
$x = 0;
$y = 0;
for($i = 1; $i <= (count($arr1) * count($arr2)); $i++){
$newoutput[] = array($arr1[($x % count($arr1))], $arr2[($y % count($arr2))]);
$x++;
$y++;
}
echo "<br />", json_encode($newoutput);
Output however, is a different order of the same output as previous.
EDIT
The second works only when (count($arrX) % count($arrY)) > 0.
I don't think there is a built in support for that.
You need to loop the arrays nested and build a result array.
$arr1 = array('A', 'B', 'C', 'D');
$arr2 = array('X', 'Y', 'Z');
foreach($arr1 as $item1){
foreach($arr2 as $item2){
$res[] = [$item1, $item2];
}
}
var_dump($res);
https://3v4l.org/CdE8Q
Try This out (This will sort out the same pair if found):
//Array 1
$arr1 = array('A', 'B', 'C', 'D', 'A', 'E'); // Same element will be sort out in pair
//Array 2
$arr2 = array('X', 'Y', 'Z' , 'X', 'Y', 'X'); // Same element will be sort out in pair
$output = array();
$used_pair = array(); // Keeping used pair
$i = 1;
foreach ($arr1 as $each1) {
foreach ($arr2 as $each2) {
if (!in_array($each1.$each2, $used_pair)) {
$output[] = array($each1, $each2);
$used_pair[] = $each1 . $each2;
}
}
}
print_r($used_pair); // array with pair string
print_r($output); // array with pair array
this is an example that ouputs unique values in the same order :
online eval : https://3v4l.org/H2pad
<?php
function cartesian(array $x,array $y): array
{
$result = [];
$size = count($x) * count($y);
$posX = 0;
$posY = 0;
for($i = 0; $i < $size; $i++) {
if (!isset($x[$posX])) {
$posX = 0;
} elseif(!isset($y[$posY])) {
$posY = 0;
}
$result[] = [$x[$posX],$y[$posY]];
$posX++; $posY++;
}
return $result;
}
$x = array('A', 'B', 'C', 'D');
$y = array('X', 'Y', 'Z');
print_r(cartesian($x,$y));
( tbh, it took me a lot of rubber duck debugging )

Get all possible pairs of n elements without duplicates with PHP

What I need
I need all possible pairs of n elements without duplicates. Let's say I've these arrays:
$arr1 = [2, 4, 6, 7];
$arr2 = [6, 5, 4, 11];
$arr3 = [22, 1, 5, 8];
$final = [
'a' => $arr1,
'b' => $arr2,
'c' => $arr3
];
What I now need is:
$pairs = [
'ab' => [$arr1, $arr2],
'ac' => [$arr1, $arr3],
'bc' => [$arr2, $arr3]
];
What I got
I come until this point:
function getPairs($array) {
$n = count($array);
$finalArray = [];
$i = 0;
foreach ($array as $a) {
for ($x = $n-1; 0 <= $x; $x--) {
if ($i != $x) {
$finalArray[] = [$array[$i], $array[$x]];
}
}
$i++;
}
return $finalArray;
}
And then:
$arr1 = [2, 4, 6, 7];
$arr2 = [6, 5, 4, 11];
$arr3 = [22, 1, 5, 8];
$merged = [$arr1, $arr2, $arr3];
$pairs = getPairs($merged);
There are two problems with my approach:
The loop produces $x = 0, $i = 1 and later $i = 1, $x = 0, which results and a duplicated array.
I don't get the keys (ab, ac, cb) with this.
Similiar to this question but with array keys: Get all the combinations of N elements of multidimensional array
To avoid duplicates, guarantee that one member of the pair always has the "lower" key. This will avoid getting pairs ac and ca.
To get the letter keys you want, use array_keys() to extract the keys from the original arrays.
function getPairs($array) {
$n = count($array);
$keys = array_keys($array);
$finalArray = [];
$i = 0;
foreach ($array as $a) {
for ($x = $n-1; $i < $x; $x--) {
$key1 = $keys[$i];
$key2 = $keys[$x];
$finalArray[$key1.$key2] = [$array[$key1], $array[$key2]];
}
$i++;
}
return $finalArray;
}
Live demo
This code should work if I understand the task properly:
$a = [[2, 4, 6, 7],[6, 5, 4, 11],[22, 1, 5, 8]];
$result = [];
$n = count($a);
for($i = 0; $i < $n-1; $i++) {
for($j = $i+1; $j < $n; $j++) {
$result[(string)$i.(string)$j] = [$a[$i], $a[$j]];
}
}
print_r($result);
Here is a "hybrid" of the other two answers:
$arr1 = [2, 4, 6, 7];
$arr2 = [6, 5, 4, 11];
$arr3 = [22, 1, 5, 8];
$final = [
'a' => $arr1,
'b' => $arr2,
'c' => $arr3
];
$n = count($final);
$keys = array_keys($final);
$pairs = [];
for($i = 0; $i < $n-1; $i++) {
for($j = $i+1; $j < $n; $j++) {
$pairs[$keys[$i] . $keys[$j]] = [$final[$keys[$i]], $final[$keys[$j]]];
}
}
print_r($pairs);

php how to cut array and add other charactor to it

I have an array like :
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
[5] => f
[6] => g
[7] => h
)
And I want add semicolon(;) every 3 index value and it's read from end of array that result is string like "ab;cde;fgh";
Here's a fun, and kind of obnoxious, one-liner:
$str = ltrim(strrev(chunk_split(implode(array_reverse($arr)), 3, ';')), ';');
Example:
$arr = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
$str = ltrim(strrev(chunk_split(implode(array_reverse($arr)), 3, ';')), ';');
echo $str; //ab;cde;fgh
// More sample output based on different input arrays:
$arr = array('a', 'b', 'c', 'd', 'e'); //ab;cde
$arr = array('a', 'b', 'c', 'd', 'e', 'f'); //abc;def
$arr = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'); //ab;cde;fgh;ijk
See demo
Its an odd way, but since you want it reversed you may need to use some function here:
$array = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
$array = array_reverse($array); // reverse it
$array = array_chunk($array, 3); // cut by threes
$string = '';
foreach ($array as $value) {
$string .= implode($value); // glue them
if(count($value) == 3) { // if still three, add a semi
$string .= ';';
}
}
$string = strrev($string); // then reverse them again
echo $string; // ab;cde;fgh
This works... there's a couple different ways to do this. This was the quickest way off the top of my head without using a second array.
$vars = array("a","b","c","d","e","f","g","h");
print_r(insert_char($vars));
function insert_char($Array, $Delimeter=";", $Count=3) {
for ($i = sizeOf($Array) - $Count; $i > 0; $i -= $Count)
array_splice($Array, $i, 0, $Delimeter);
return implode($Array);
}
Result
ab;cde;fgh
Here's my solution, although it feels inefficient it is pretty clear:
<?php
$myarr=Array('a','b','c','d','e','f','g','h');
$newarr=Array();
$arrsize = sizeof($myarr);
for ($x = 0, $i = 0; $x < $arrsize; $x++, $i++) {
$newarr[$i] = $myarr[$arrsize - $x - 1];
if (($arrsize - $x) % 3 == 0) {
$i++;
$newarr[$i] = ";";
}
}
$newarr = array_reverse($newarr);
print_r($newarr);
?>
Just traversing it from backward and joining the string in reverse too gives that result.
$vars = array("a","b","c","d","e","f","g");
$c = 0; $s = "";
for ($i = sizeof($vars)-1; $i >= 0; $i--)
{
$c++;
$s = $vars[$i].$s;
if ($c == 3) { $c = 0; $s = ";".$s; }
}
echo $s;

Categories