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 )
Related
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)
Say I have an array of strings like this:
$in_arr = ['a', 'a', 'b', 'b', 'a', 'b', 'b', 'a', 'a', 'b'];
I would like an efficient way to merge all a's into a single value but leave the b's untouched so the result will be:
['a', 'b', 'b', 'a', 'b', 'b', 'a', 'b']
This is a possible solution:
<?php
define('ASPECT', 'a');
$input = ['a', 'a', 'b', 'b', 'a', 'b', 'b', 'a', 'a', 'b'];
$output = [];
array_walk($input, function($entry) use (&$output) {
if (($entry != ASPECT) || (end($output) != ASPECT)) {
$output[] = $entry;
}
});
print_r($output);
The output obviously is:
Array
(
[0] => a
[1] => b
[2] => b
[3] => a
[4] => b
[5] => b
[6] => a
[7] => b
)
With array_reduce:
$res = array_reduce($arr, function ($c, $i) {
if ( $i!='a' || end($c)!='a' )
$c[] = $i;
return $c;
}, []);
You could iterate through the list and only add strings to a new list if they're not your key string or if they are different from the previous string, something like this:
$in_arr = ['a', 'a', 'b', 'b', 'a', 'b', 'b', 'a', 'a', 'b'];
$new_arr = [];
$last = '';
$key = 'a';
foreach ($in_arr as $item) {
if ($key == $item and $item == $last) {
continue;
}
$last = $item;
array_push($new_arr, $item);
}
echo "[";
foreach( $new_arr as $value ){
echo $value.", ";
}
echo "]";
produces
[a, b, b, a, b, b, a, b, ]
Edit: PHP sandbox
You Require code :
<?php
$in_arr = array('a', 'a', 'b', 'b', 'a', 'b', 'b', 'a', 'a', 'b');
$last_temp = '';
for($i=0;$i<count($in_arr);$i++)
{
if($last_temp == $in_arr[$i] && $in_arr[$i]=='a')
{
unset($in_arr[$i]);
$in_arr = array_values($in_arr);
}
else
{
$last_temp = $in_arr[$i];
}
}
echo json_encode($in_arr);
Output :
["a","b","b","a","b","b","a","b"]
An array of values are provided in the order they should appear in columns. For example, the second value in the array should be displayed on a webpage beneath the first instead of on its right.
Task: Reorder the array so that the values are in the order they will be output in html. The data for the first row must be first in the output.
Example inputs:
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
Example output:
[['A', 'E'], ['B','F'], ...]
Use array_chunk() to break the array up in to $cols:
$chunks = array_chunk($array, ceil(count($array) / $cols));
Which would give you:
array(array('A', 'B', 'C', 'D'), array('E', 'F', 'G'));
Then combine the values from each array where the keys match.
array_unshift($chunks, null);
$chunks = call_user_func_array('array_map', $chunks);
// array(array('A', 'E'), array('B', 'F'), array('C', 'G'), array('D', NULL))
Here's an example
You need to count offset and then iterate over an array:
$input = array('A', 'B', 'C', 'D', 'E', 'F', 'G');
$cols = 2;
$itemsCount = count($input);
$offset = ceil($itemsCount/$cols);
$result = array();
for($i = 0; $i < $itemsCount; ++$i) {
if (isset($input[$i]) && isset($input[$i + $offset])) {
$result[] = array($input[$i], $input[$i + $offset]);
}
}
The modern functional equivalent of #billyonecan's approach uses the spread operator to transpose the data after it has been "chunked" to the correct size. (Demo)
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
var_export(
array_map(
null,
...array_chunk($input, ceil(count($input) / 2))
)
);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D', null]]
A classic loop alternative using a modulus calculation is also attractive because it doesn't generate the extra null element in the final set when the division doesn't come out even: (Demo)
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
$rows = ceil(count($input) / $cols);
$result = [];
foreach ($input as $i => $value) {
$result[$i % $rows][] = $value;
}
var_export($result);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D']]
On this related topic, to more simply chunk and transpose with a finite number of rows, use the following: (Demo)
$rows = 2;
var_export(
array_map(
null,
...array_chunk($input, $rows)
)
);
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;
Consider the following array as input:
$input = array('A', 'B', 'C', 'D');
I'm looking for a way to make loop though this array, writing down every possible pair of two values. In this example: AB AC AD BC BD CD. Please not that BA doesn't count as a pair, since AB is already mentioned:
$output = array(
'A' => 'B',
'A' => 'C',
'A' => 'D',
'B' => 'C',
'B' => 'D'
);
Any input on how to get this started is appreciated!
$output=array();
for ($i=0;$i<sizeof($input);$i++) {
$k=$input[$i];
for ($j=$i+1;$j<sizeof($input);$j++) {
$v=$input[$j];
$output[]=array($k=>$v);
}
}
Edit
As of your comment, the restructured output
$output=array();
//See below
for ($i=0;$i<sizeof($input);$i++) {
$k=$input[$i];
$v=array();
for ($j=$i+1;$j<sizeof($input);$j++) {
$v[]=$input[$j];
}
$output[]=array($k=>$v);
}
This will give you 'D'=>Array() as a last row, if you don't want hti you have to change
for ($i=0;$i<sizeof($input);$i++) {
to
for ($i=0;$i<sizeof($input)-1;$i++) {
something like this maybe;
$input = array('A', 'B', 'C', 'D');
$input_copy = $input;
$output = array();
$i = 0;
foreach($input as $val) {
$j = 0;
foreach($input_copy as $cval) {
if($j < $i) break;
$output[] = array($val => $cval);
$j++;
}
$i++;
}
$output = array(
0 => array('A' => 'A'),
1 => array('A' => 'B'),
2 => array('A' => 'C'),
...
);
Note that your output array is impossible, as the key is overwritten each time
This won't be possible in PHP, as PHP array can have only unique keys.
You can get output as
$output = array(
'A' => array('B','C','D'),
'B' => array('C','D')
);
$input = array('A', 'B', 'C', 'D');
foreach($input as $key => $value){
$tempKey = $key;
for($key +1 ; $key < count($input) ; $key++){
$result[$tempKey][] = $input[$key];
}
}
You can use this generic method:
function combine($inputArray, &$outputArray, $index, $combLen) {
global $outstr;
for ($i = $index; $i < count($inputArray); $i++) {
$outstr.=$inputArray[$i];
if(strlen($outstr) == $combLen) {
$outputArray[]= $outstr;
}
combine($inputArray, $outputArray, $i + 1, $combLen);
$outstr = substr($outstr, 0, strlen($outstr)-1);
}
}
See it on ideone
if you need to work with pairs as arrays
$pairs = [];
foreach($a as $k => $v) {
foreach(array_slice($a, $k + 1) as $k2 => $v2) {
$pairs[] = [$v, $v2];
}
}