Combining of array items - php

I have a problem with an advanced loop, this are my arrays
$array1 = array(1,2,3);
$array2 = array(4,5);
$array3 = array(6,7,8,9);
$array4 = array(10,11);
I want to loop with the following result:
1,4,6,10
1,4,6,11
1,4,7,10
1,5,7,11
With the last: 3,5,8,11
How can I do that?

Solution for a variable number of arrays. Can probably be written a bit shorter, but I leave that to you. ;)
<?php
$array1 = array(1,2,3);
$array2 = array(4,5);
$array3 = array(6,7,8,9);
$array4 = array(10,11);
function turboArray()
{
$arrays = func_get_args();
$indexes = array_fill(0, count($arrays), 0);
function turboSubArray(&$arrays, &$indexes, $l){
for ($a = 0; $a < count($arrays[$l]); $a++){
$indexes[$l] = $a;
if ($l == count($arrays) - 1) {
for ($i = 0; $i < count($indexes); $i++)
{
echo $arrays[$i][$indexes[$i]];
if ($i == count($indexes) - 1){
echo "\n<br/>";
$indexes[$i] = 0;
if ($i == 0) return;
}
else {
echo ', ';
}
}
} else if ($l < count($indexes)) {
turboSubArray($arrays, $indexes, $l + 1);
}
}
}
$l = 0;
turboSubArray($arrays, $indexes, $l);
}
turboArray($array1, $array2, $array3, $array4);

This should do it... ?
foreach ($array1 as $first) {
foreach ($array2 as $second) {
foreach ($array3 as $third) {
foreach ($array4 as $fourth) {
echo "$first $second $third $fourth";
}
}
}
}

I got bored and decided to overengineer a bit. Enjoy.
class CrossJoin implements Iterator {
private $arrays = array();
private $index = 0;
public function __construct(/* $array1, ... */) {
foreach (func_get_args() as $arr) {
// ArrayIterator's iteration stuff is cleaner than arrays',
// and less prone to breakage when objects are passed around
if (count($arr)) $this->arrays[] = new ArrayIterator($arr);
}
// if any of the arrays were empty, a cross join should fail.
// fudge a single empty array to prevent special-casing later
if (count($this->arrays) !== func_num_args()) {
$this->arrays = array(new ArrayIterator(array()));
}
}
public function next() {
for ($i = count($this->arrays) - 1; $i >= 0; --$i) {
// carry til we don't have to anymore
$place = $this->arrays[$i];
$place->next();
if ($place->valid()) break;
}
// if $i<0, then we carried right off the edge of the list.
// don't let $arrays[0] be reset, cause that's our indicator
// that we're done.
if ($i<0) return;
++$this->index;
for (++$i; $i < count($this->arrays); ++$i) {
$this->arrays[$i]->rewind();
}
}
public function current() {
$result = array();
foreach ($this->arrays as $arr) { $result[] = $arr->current(); }
return $result;
}
public function key() { return $this->index; }
public function valid() {
return !empty($this->arrays) && $this->arrays[0]->valid();
}
public function rewind() {
foreach ($this->arrays as $arr) $arr->rewind();
$this->index = 0;
}
}
$combos = new CrossJoin(
array(1, 2, 3),
array(4, 5),
array(6, 7, 8, 9),
array(10, 11)
);
foreach ($combos as $combo) {
echo implode(', ', $combo), "\n";
}

Hope that helps:
for ($i = 0; $i < count($a1); ++i) {
for ($j = 0; $j < count($a2); ++j) {
for ($k = 0; $k < count($a3); ++k) {
for ($l = 0; $l < count($a4); ++l) {
echo $a1[$i] . ' ' . $a2[$j] . ' ' . $a3[$k] . ' ' . $a4[$l] . '\n';
}
}
}
}
Cheers!

You are looking for the PHP array_merge function.

Related

Number of unique pairs in an array - in php

Input: arr[] = {1, 1, 2} ;
Output: 4 ;
(1, 1), (1, 2), (2, 1), (2, 2) are the only possible pairs.
I tried below code
$temp = [];
for($i=0; $i<count($a); $i++) {
for($j=1;$j<count($a);$j++) {
$temp[] = array(0=>$a[$i],1=>$a[$j]);
}
}
for($i=0;$i<count($temp);$i++) {
if(!empty($temp1)) {
for($j=0;$j<count($temp1);$j++) {
if($temp1[$j][0] != $temp[$i][0] || $temp1[$j][1] != $temp[$i][1]) {
$temp1[$j][0] = $temp[$i][0];
$temp1[$j][1] = $temp[$i][1];
}
}
} else {
$temp1[$j][0] = $temp[$i][0];
$temp1[$j][1] = $temp[$i][1];
}
}
print_r($temp1);
Start by removing duplicates from your array. Then you can generate all pairs easily.
$a = [1,1,2];
$b = [];
$temp = [];
// if you want to do it yourself
for($i= 0; $i<count($a); $i++) {
if (!in_array($a[$i], $b)) {
$b[] = $a[$i];
}
}
// if you want to use built-in
$b = array_values(array_unique($a));
for($i=0; $i<count($b); $i++) {
for($j=0;$j<count($b);$j++) {
$temp[] = array(0=>$b[$i],1=>$b[$j]);
}
}
print_r($temp);

how to make array combination with unique value and limited character?

i have a array like this
['1', '2', '3', '4']; I want to make result of the array like this
['123', '124', '132', '134', '142', '143', '213' ,' 214', '231', '234', '241', '243', '312', '314', '321', '324', '341', '342', '412', '413', '421', '423', '431', '423']
this is my code
<?php
ini_set('memory_limit', '-1');
function permute($arg) {
$array = is_string($arg) ? str_split($arg) : $arg;
if(1 === count($array))
return $array;
$result = array();
foreach($array as $key => $item)
foreach(permute(array_diff_key($array, array($key => $item))) as $p)
$result[] = $item . $p;
return $result;
}
$array = array('1','2','3','4');
var_dump(permute($array));
?>
the result of my code is
['1234', '1243', '1324', '1342', '1423', '1432', '2134', '2314', '2413' ......... ]
i want to limit character of result just 3 character. how to make it?
<?php
function combination($chars, $size, $combinations = array()) {
if (empty($combinations)) {
$combinations = $chars;
}
# we're done if we're at size 1
if ($size == 1) {
return $combinations;
}
$new_combinations = array();
foreach ($combinations as $combination) {
foreach ($chars as $char) {
$new_combinations[] = $combination . $char;
}
}
return combination($chars, $size - 1, $new_combinations);
}
function permute($array, $numberOfChar)
{
$output = combination($array, $numberOfChar);
$result = array_values(array_filter($output,function($str){
for($i = 0; $i < strlen($str); $i++)
{
for($j = $i + 1; $j < strlen($str); $j++)
{
if($str[$i] == $str[$j])
{
return false;
}
}
}
return true;
}));
return $result;
}
$array = array(1,2,3,4);
print_r(permute($array, 3)); // pass an array an num of permute char

PHP - How to create all possibility from a string

Here, there is a example string "XjYAKpR" .. how to create all new string possibility with that string ??
I've tried before
function containAllRots($s, $arr) {
$n = strlen($s);
$a = array();
for ($i = 0; $i < $n ; $i++) {
$rotated = rotate(str_split($s), $i);
$a[] = $rotated;
}
print_r($a);die();
if (array_diff($arr, $a)) {
return True;
}
else
{
return False;
}
}
I make 2 function rotate and generate
function rotate($l, $n) {
$b = $l[$n];
$sisa = array_values(array_diff($l, array($b)));
for ($i = 0; $i < count($sisa) ; $i++) {
$random[] = generate($sisa, $b);
}
print_r($random);die();
$hasil = $l[$n] . implode("",$random);
return $hasil;
}
function generate($sisa, $b) {
$string = implode("",$sisa);
$length = count($sisa);
$size = strlen($string);
$str = '';
for( $i = 0; $i < $length; $i++ ) {
$str .= $string[ rand( 0, $size - 1 ) ];
}
Here there is a pair of functions that lets you calculate a permutation set
(no repetitions are taken in account)
function extends_permutation($char, $perm) {
$result = [];
$times = count($perm);
for ($i=0; $i<$times; $i++) {
$temp = $perm;
array_splice($temp, $i, 0, $char);
array_push($result, $temp);
}
array_push($result, array_merge($perm, [$char]));
return $result;
}
function extends_set_of_permutations($char, $set) {
$step = [];
foreach ($set as $perm) {
$step = array_merge($step, extends_permutation($char, $perm));
}
return $step;
}
you can use them to generate the required set of permutations. Something like this:
$seed = "XjYAKpR";
// the first set of permutations contains only the
// possible permutation of a one char string (1)
$result_set = [[$seed[0]]];
$rest = str_split(substr($seed,1));
foreach($rest as $char) {
$result_set = extends_set_of_permutations($char, $result_set);
}
$result_set = array_map('implode', $result_set);
sort($result_set);
At the end of the execution you will have the 5040 permutations generated by your string in the result_set array (sorted in alphabetical order).
Add a char and you will have more than 40000 results.
The functions are quite naive in implementation and naming, both aspects can be improved.

How to create a 2D array that values BA and AB are treated as the same

I am trying to create function that allows me to get all combinations of an array to later generate a list.
But my problem is that currently my function treat "ab" as different from "ba". I dont know how to explain it in words but I guess the picture below exemplify what I try to achieve.
function everyCombination($array) {
$arrayCount = count($array);
$maxCombinations = pow($arrayCount, $arrayCount);
$returnArray = array();
$conversionArray = array();
foreach ($array as $key => $value) {
$conversionArray[base_convert($key, 10, $arrayCount)] = $value;
}
for ($i = 0; $i < $maxCombinations; $i++) {
$combination = base_convert($i, 10, $arrayCount);
$combination = str_pad($combination, $arrayCount, "0", STR_PAD_LEFT);
$returnArray[] = strtr($combination, $conversionArray);
}
return $returnArray;
}
$a = everyCombination(array('a', 'b', 'c','d'));
print_r($a);
The desired ouput would be
a
ab
abc
abcd
b
bc
bcd
c
cd
d
What you need to do is iterate through the array recursively, for each recursion you should only iterate through all the greater elements. Like so:
function everyCombination($arr) {
$combos = array();
$len = count($arr);
for( $i=0; $i<$len; $i++) {
for( $j=$i+1; $j<=$len; $j++) {
$combos[] = implode("",array_slice($arr,$i,$j-$i));
}
}
return $combos;
}
Example call:
everyCombination(['a','b','c','d']);
Returns:
['a','ab','abc','abcd','b','bc','bcd','c','cd','d']
It seems that you're after consecutive results, so a double loop would be a better choice here; recursion requires more control.
function combos($array)
{
if (!$array) {
return [];
}
$n = count($array);
$r = [];
for ($i = 0; $i < $n; ++$i) {
$prefix = '';
for ($j = $i; $j < $n; ++$j) {
$r[] = $prefix . $array[$j];
$prefix .= $array[$j];
}
}
return $r;
}
print_r(combos([1, 2, 3, 4]));

Cartesian Product of N arrays

I have a PHP array which looks like this example:
$array[0][0] = 'apples';
$array[0][1] = 'pears';
$array[0][2] = 'oranges';
$array[1][0] = 'steve';
$array[1][1] = 'bob';
And I would like to be able to produce from this a table with every possible combination of these, but without repeating any combinations (regardless of their position), so for example this would output
Array 0 Array 1
apples steve
apples bob
pears steve
pears bob
But I would like for this to be able to work with as many different arrays as possible.
this is called "cartesian product", php man page on arrays http://php.net/manual/en/ref.array.php shows some implementations (in comments).
and here's yet another one:
function array_cartesian() {
$_ = func_get_args();
if(count($_) == 0)
return array(array());
$a = array_shift($_);
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
$cross = array_cartesian(
array('apples', 'pears', 'oranges'),
array('steve', 'bob')
);
print_r($cross);
You are looking for the cartesian product of the arrays, and there's an example on the php arrays site: http://php.net/manual/en/ref.array.php
Syom copied http://www.php.net/manual/en/ref.array.php#54979 but I adapted it this to become an associative version:
function array_cartesian($arrays) {
$result = array();
$keys = array_keys($arrays);
$reverse_keys = array_reverse($keys);
$size = intval(count($arrays) > 0);
foreach ($arrays as $array) {
$size *= count($array);
}
for ($i = 0; $i < $size; $i ++) {
$result[$i] = array();
foreach ($keys as $j) {
$result[$i][$j] = current($arrays[$j]);
}
foreach ($reverse_keys as $j) {
if (next($arrays[$j])) {
break;
}
elseif (isset ($arrays[$j])) {
reset($arrays[$j]);
}
}
}
return $result;
}
I needed to do the same and I tried the previous solutions posted here but could not make them work. I got a sample from this clever guy http://www.php.net/manual/en/ref.array.php#54979. However, his sample did not managed the concept of no repeating combinations. So I included that part. Here is my modified version, hope it helps:
$data = array(
array('apples', 'pears', 'oranges'),
array('steve', 'bob')
);
$res_matrix = $this->array_cartesian_product( $data );
foreach ( $res_matrix as $res_array )
{
foreach ( $res_array as $res )
{
echo $res . " - ";
}
echo "<br/>";
}
function array_cartesian_product( $arrays )
{
$result = array();
$arrays = array_values( $arrays );
$sizeIn = sizeof( $arrays );
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof( $array );
$res_index = 0;
for ( $i = 0; $i < $size; $i++ )
{
$is_duplicate = false;
$curr_values = array();
for ( $j = 0; $j < $sizeIn; $j++ )
{
$curr = current( $arrays[$j] );
if ( !in_array( $curr, $curr_values ) )
{
array_push( $curr_values , $curr );
}
else
{
$is_duplicate = true;
break;
}
}
if ( !$is_duplicate )
{
$result[ $res_index ] = $curr_values;
$res_index++;
}
for ( $j = ( $sizeIn -1 ); $j >= 0; $j-- )
{
$next = next( $arrays[ $j ] );
if ( $next )
{
break;
}
elseif ( isset ( $arrays[ $j ] ) )
{
reset( $arrays[ $j ] );
}
}
}
return $result;
}
The result would be something like this:
apples - steve
apples - bob
pears - steve
pears - bob
oranges - steve
oranges - bob
If you the data array is something like this:
$data = array(
array('Amazing', 'Wonderful'),
array('benefit', 'offer', 'reward'),
array('Amazing', 'Wonderful')
);
Then it will print something like this:
Amazing - benefit - Wonderful
Amazing - offer - Wonderful
Amazing - reward - Wonderful
Wonderful - benefit - Amazing
Wonderful - offer - Amazing
Wonderful - reward - Amazing
foreach($parentArray as $value) {
foreach($subArray as $value2) {
$comboArray[] = array($value, $value2);
}
}
Don't judge me..
This works I think - although after writing it I realised it's pretty similar to what others have put, but it does give you an array in the format requested. Sorry for the poor variable naming.
$output = array();
combinations($array, $output);
print_r($output);
function combinations ($array, & $output, $index = 0, $p = array()) {
foreach ( $array[$index] as $i => $name ) {
$copy = $p;
$copy[] = $name;
$subIndex = $index + 1;
if (isset( $array[$subIndex])) {
combinations ($array, $output, $subIndex, $copy);
} else {
foreach ($copy as $index => $name) {
if ( !isset($output[$index])) {
$output[$index] = array();
}
$output[$index][] = $name;
}
}
}
}
#user187291
I modified this to be
function array_cartesian() {
$_ = func_get_args();
if (count($_) == 0)
return array();
$a = array_shift($_);
if (count($_) == 0)
$c = array(array());
else
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
so it returns that all-important empty array (the same result as no combinations) when you pass 0 arguments.
Only noticed this because I'm using it like
$combos = call_user_func_array('array_cartesian', $array_of_arrays);
function array_comb($arrays)
{
$result = array();
$arrays = array_values($arrays);
$sizeIn = sizeof($arrays);
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof($array);
for ($i = 0; $i < $size; $i ++)
{
$result[$i] = array();
for ($j = 0; $j < $sizeIn; $j ++)
array_push($result[$i], current($arrays[$j]));
for ($j = ($sizeIn -1); $j >= 0; $j --)
{
if (next($arrays[$j]))
break;
elseif (isset ($arrays[$j]))
reset($arrays[$j]);
}
}
return $result;
}
I had to make combinations from product options. This solution uses recursion and works with 2D array:
function options_combinations($options) {
$result = array();
if (count($options) <= 1) {
$option = array_shift($options);
foreach ($option as $value) {
$result[] = array($value);
}
} else {
$option = array_shift($options);
$next_option = options_combinations($options);
foreach ($next_option as $next_value) {
foreach ($option as $value) {
$result[] = array_merge($next_value, array($value));
}
}
}
return $result;
}
$options = [[1,2],[3,4,5],[6,7,8,9]];
$c = options_combinations($options);
foreach ($c as $combination) {
echo implode(' ', $combination)."\n";
}
Elegant implementation based on native Python function itertools.product
function direct_product(array ...$arrays)
{
$result = [[]];
foreach ($arrays as $array) {
$tmp = [];
foreach ($result as $x) {
foreach ($array as $y) {
$tmp[] = array_merge($x, [$y]);
}
}
$result = $tmp;
}
return $result;
}

Categories