I'm having an array for example with 4 elements array("a", "b", "c", d"); what is the fastest way to repeat this array to create a new array with a certain length, e.g 71 elements?
// the variables
$array = array("a", "b", "c", "d");
$desiredLength = 71;
$newArray = array();
// create a new array with AT LEAST the desired number of elements by joining the array at the end of the new array
while(count($newArray) <= $desiredLength){
$newArray = array_merge($newArray, $array);
}
// reduce the new array to the desired length (as there might be too many elements in the new array
$array = array_slice($newArray, 0, $desiredLength);
Solution using SPL InfiniteIterator:
<?php
function fillArray1($length, $values) {
foreach (new InfiniteIterator(new ArrayIterator($values)) as $element) {
if (!$length--) return $result;
$result[] = $element;
}
return $result;
}
var_dump(fillArray(71, array('a', 'b', 'c', 'd')));
The real SPL hackers might have dropped the if (!$length--) break; and instead used a limit iterator: new LimitIterator(new InfiniteIterator(new ArrayIterator($values)), 0, $length), but I thought that to be overkill...
A simple solution using each() and reset() and the array's internal pointer:
<?php
$array = array('a', 'b', 'c', 'd');
$length = 71;
$result = array();
while(count($result) < $length)
{
$current = each($array);
if($current == false)
{
reset($array);
continue;
}
$result[] = $current[1];
}
echo count($result); // Output: 71
In order to join this club:
$result = call_user_func_array('array_merge', array_fill(0, ceil($size/count($array)), $array));
while(count($result) > $size) array_pop($result);
You asked for the fastest so I did a benchmark (Source: http://pastebin.com/G5w7QJPU)
Kau-Boy: 5.40128803253
Frxstrem: 5.00970411301
NikiC: 4.12150001526
user2469998: 0.561513900757
Alexander: 1.92847204208
Hammerite: 2.17130494118
Max: 12.9516701698
Evert: 1.9378361702
Christoph: 1.6862449646
Test took 35.7696909904s
user2469998 is the fastest but it only works for string values with single chars (or the same length if you use second parameter of str_split).
$newarray = array();
$i = 0;
$oldarrayvalues = array_values($oldarray);
$oldarraysize = count($oldarrayvalues);
if ( $oldarraysize ) {
while ( count($newarray) < DESIRED_ARRAY_SIZE ) {
$newarray[] = $oldarrayvalues[$i];
$i++;
$i %= $oldarraysize;
}
}
If you have PHP 5.3 available, you can also try this:
function fill(array $initalArray, $toCount) {
$initialArrayCount = count($initalArray);
$fillUp = function(array $filledUpArray, $missingCount)
use(&$fillUp, $initalArray, $initialArrayCount, $toCount)
{
if($missingCount <= 0) return array_slice($filledUpArray, 0, $toCount);
return $fillUp(array_merge($filledUpArray, $initalArray), $missingCount - $initialArrayCount);
};
return $fillUp($initalArray, $toCount - $initialArrayCount);
}
$theArray = array("a", "b", "c", "d");
$toLength = 71;
$filledArray = fill($theArray, $toLength);
print_r($filledArray);
<?php
$array = array('a', 'b', 'c', 'd');
$end = 71;
$new_array = array();
while(count($new_array) <= $end)
{
foreach($array as $key => $value)
{
$new_array[] = $value;
}
}
$new_array = array_slice($new_array, 0, $end);
Tested and works.
You can test for yourself by adding this:
echo '<pre>';
print_r($new_array);
echo '</pre>';
$array = array("a", "b", "c", "d");
$merge = array();
$desiredLength = 71;
while(2 * count($array) <= $desiredLength){
$array = array_merge($array, $array);
}
if($desiredLength > count($array))
$merge = array_slice($array, 0, $desiredLength - count($array));
$array = array_merge($array, $merge);
$array = array_slice($array, 0, $desiredLength);
print_r($array);
$arr = array("a", "b", "c", "d");
$len = 71;
$a = array();
$a = str_split( substr( str_repeat( join( $arr), ceil( $len / count( $arr))), 0, $len));
var_export($a);
I think that user2469998 was closest but just not that nice.
For my example, I use pipe to implode and the str_repeat function to build a string that meets the length, explode it back apart and trim the fat.
$list = array('a','b','c','d');
$length = 6;
$result = array_slice(explode('|', str_repeat(implode('|', $list).'|',ceil($length/count($list)))), 0, $length);
Many ways to achieve this but thought I'd share mine. The only restriction is that you need to use a character to implode and explode on which isn't part of the array items or the exploder won't work properly.
:)
Related
I have an Associative array as
$array = Array([0]=>a[1]=>b[2]=c[3]=>d);
I need to build an array from this array where the the first key becomes a and the value becomes b & 2nd key becomes c and value becomes d.
Output should be:
$finalarray = Array([a]=>b,[c]=>d);
I have tried this following code:
foreach($array as $key=>$value){
$arr[$value] = array_slice($array, 1, 1);
$finalarray[] = $arr;
}
Please help me with this!
The best way is to loop on your first array, but to skip one value on two:
$array = array("a", "b", "c", "d");
$finalArray = array();
for ($i = 0; $i < count($array); $i+=2) {
$finalArray[$array[$i]] = $array[$i + 1];
}
This may help:
$a = array('a','b','c','d'); $b = array();
$length = count(a)%2 ? count($a)-1 : count($a);
for($i=0; $i<$length; $i++){
$b[$a[$i]] = $a[++$i];
}
var_dump($a,$b);
Little changed your code:
$i=0;
foreach($array as $key=>$value){
$value_2=$value++;
if($i%2==0)
$arr[$value_2] =$value;
$i++;
//$finalarray[] = $arr;
}
echo"<pre>";
print_r($arr);
If your array is associative , below code may help you
<?php
$array = array(0=>'a',1=>'b',2=>'c',3=>'d');
$new_array = array();
for($i=0;$i<count($array);$i+=2)
{
$new_array[$array[$i]] = $array[$i+1];
}
print_r($new_array);
?>
I want to merge / mix two arrays together, but I want it to be randomly "mixed" however NOT shuffled. For example:
$first = [1, 2, 3, 4];
$second = [10, 20, 30, 40];
Possible desired "mixes" are:
[1, 10, 20, 30, 2, 40, 3, 4]
[10, 1, 2, 20, 30, 3, 4, 40]
[1, 2, 3, 10, 20, 4, 30, 40]
Note that if we pluck the values back out we would still have the original orders of:
1, 2, 3, 4
10, 20, 30, 40
Well, there's (yet another) one possible approach:
$arr = call_user_func_array('array_merge', array_map(null, $first, $second));
print_r($arr); // [1, 10, 2, 20, 3, 30, 4, 40];
Demo. That's apparently deterministic; for random ordering each pair should be shuffled additionally. For example:
function zipShuffle($first, $second) {
return call_user_func_array('array_merge', array_map(function($a, $b) {
return mt_rand(0, 1) ? [$a, $b] : [$b, $a];
}, $first, $second));
}
... but that obviously won't be able to churn out something like [1,2,3,10,20...]. If this is required, here's another solution:
function orderedShuffle($first, $second) {
$results = [];
$stor = [$first, $second];
$i = mt_rand(0, 1);
// switching between arrays on the fly
while (list(, $v) = each($stor[$i])) {
$results[] = $v;
$i = mt_rand(0, 1);
}
// one array is gone, now we need to add all the elements
// of the other one (as its counter left where it was)
$i = 1 - $i;
while (list(, $v) = each($stor[$i])) {
$results[] = $v;
}
return $results;
}
Demo. The last function is actually quite easy to extend for as many arrays as required.
Can you try this,
<?php
$first = array(1,2,3,4);
$second = array(10,20,30,40);
$arrayMixed=array();
$firstReverse=array_reverse($first);
$secondReverse=array_reverse($second);
$firstReverseCount = count($firstReverse);
$secondReverseCount = count($secondReverse);
foreach($firstReverse as $key=>$val) {
if ($firstReverseCount>0) {
array_push($arrayMixed, array_pop($firstReverse));
if ($secondReverseCount>0) {
array_push($arrayMixed, array_pop($secondReverse));
}
}
}
$ArrayMixeddata = array_merge($arrayMixed, $second);
echo "<pre>";
print_r($ArrayMixeddata);
echo "</pre>";
?>
Not quick ways, but them works.
// with permutations
function combineShuffleOrder($first, $second)
{
// combine into one array with alternation
$firstLen = count($first);
$secondLen = count($second);
$max = max($firstLen, $secondLen);
$result = array();
for($i=0; $i < $max; $i++) {
if ($i < $firstLen)
$result[] = $first[$i];
if ($i < $secondLen)
$result[] = $second[$i];
}
// "shuffle" with permutation
$len = count($result);
for($i=1; $i<$len; $i++) {
if (rand(1, 3) % 2 == 0) {
$tmp = $result[$i-1];
$result[$i-1] = $result[$i];
$result[$i] = $tmp;
$i++; // skip one exchange
}
}
return $result;
}
// with using "shuffle" in subarray
function combineShuffleOrder2($first, $second)
{
// combine into one array with alternation
$firstLen = count($first);
$secondLen = count($second);
$max = max($firstLen, $secondLen);
$result = array();
for($i=0; $i < $max; $i++) {
$sub = array();
if ($i < $firstLen)
$sub[] = $first[$i];
if ($i < $secondLen)
$sub[] = $second[$i];
shuffle($sub);
$result = array_merge($result, $sub);
}
return $result;
}
// with using "shuffle" in subarray if sources arrays are equals by length
function combineShuffleOrder3($first, $second)
{
$max = count($first);
$result = array();
for($i=0; $i < $max; $i++) {
$sub = array(
$first[$i],
$second[$i]
);
shuffle($sub);
$result = array_merge($result, $sub);
}
return $result;
}
$first = array(1,2,3,4);
$second = array(10,20,30,40);
print_r(combineShuffleOrder($first, $second));
print_r(combineShuffleOrder2($first, $second));
print_r(combineShuffleOrder3($first, $second));
I recommend forming a single array of the two input arrays for simpler toggling. Simply loop and consume one element from a randomly selected array and push that selection into the result array. When the pool of arrays is reduced to a single array, kill the loop and append the remaining elements of the last surviving array onto the result array.
I'll use a pool of four arrays (one which is empty from the beginning) to demonstrate that the snippet is robust enough to handle a variable number of arrays, a variable number of elements in each array, and empty arrays.
Code: (Demo)
$first = [1, 2, 3, 4];
$second = [10, 20, 30, 40];
$third = [];
$fourth = ['a', 'b'];
$pool = [$first, $second, $third, $fourth];
$result = [];
while (count($pool) > 1) {
$pullFrom = array_rand($pool);
if (!$pool[$pullFrom]) {
unset($pool[$pullFrom]);
continue;
}
$result[] = array_shift($pool[$pullFrom]);
}
var_export(array_merge($result, ...$pool));
Alternatively without array_merge() and count() calls, but it makes more iterated calls of array_shift(): (Demo)
$pool = [$first, $second, $third, $fourth];
$result = [];
while ($pool) {
$pullFrom = array_rand($pool);
if (!$pool[$pullFrom]) {
unset($pool[$pullFrom]);
continue;
}
$result[] = array_shift($pool[$pullFrom]);
}
var_export($result);
Loop this script until both arrays are done.
$j = 0;
$i = 0;
$r = rand(0, 1);
if($r == 0) {
$ret .= $array1[$i];
$i++;
} elseif($r == 1) {
$ret .= $array2[$j];
$j++;
}
Of course, you have to handle a few exceptions in this code, but it might be the route.
My brain is broken. Here's the concept:
$a = array('please', 2);
$s = array('help', 3);
$d = array('me', 1);
$f = array('!', 3);
$g = array('asdf', 1);
$myArray = array($a, $s, $d, $f, $g);
for ($i = 0; $i < count($myArray); $i++) {
// code here
}
Code should contain logic that removes indexes 0, 3, and 4 from myArray because they contain the last value of their kinds (last 2, 3, and 1 respectively) at position $myArray[$i][1].
--EDIT:
Adapted suggestions from comments to get this:
$a = array('please', 2);
$s = array('help', 3);
$d = array('me', 1);
$f = array('!', 3);
$g = array('asdf', 1);
$myArray = array($a, $s, $d, $f, $g);
$used = array();
for ($i = 0; $i < count($myArray); $i++) {
$used[$myArray[$i][1]] = $i;
}
foreach ($used as $deleteMe)
unset($myArray[$deleteMe]);
$newArray = array_values($myArray);
var_dump($newArray);
It works, and creating a new array with array_values eliminates the gaps created by using unset().
$i = count($myArray);
$used = array();
while ($i-- > 0)
if (!isset($used[$myArray[$i][1]])) {
$used[$myArray[$i][1]] = true;
unset($myArray[$i]);
}
This simple snippet first iterates from the back over the array and deletes the index if an entry with this number wasn't deleted yet.
Iterate through $myArray, save last position of every kind in $otherArray, loop through $otherArray unseting items from $myArray. That's all.
Let's say I have two variables, strings converted to arrays
$VAR_1 = '1-1:2-1';
$VAR_1 = Explode(':', $VAR_1);
$VAR_2 = '3-1:4-1:2-2:2-3:2-4';
$VAR_2 = Explode(':', $VAR_2);
Now I want 'all' combinations of VAR_1 and VAR_2 mixed set into a new array $COMB
But at least 1, or both variable(s) of VAR_1 must be in the new array, and the combined string must consists of 5 variables.
I need ALL combinations, also duplicate, but which are in a different order.
How to achieve this ?
Scenario: Poker Game (VAR_1 = player cards (color - number) VAR_2 = table cards)
{
$array1 = array(0 => 'zero_a', 2 => 'two_a', 3 => 'three_a');
$array2 = array(1 => 'one_b', 3 => 'three_b', 4 => 'four_b');
$result = $array1 + $array2;
var_dump($result);
}
First, you need to create an array of all 7 variables, using simple
$arr3 = $arr1 + $arr2;
or
$arr3 = array_merge($arr1, $arr2);
Then, you need to select 5-element groups, that means 2 element will always be skipped out, these 2 elements will have indexes $i and $j, making 2 nested for cycles an excelent solution for this problem, here's an example:
$array = array("1-2", "1-5", "1-8", "3-4", "2-1", "2-2", "1-6");
$result = array(); //not sure if this line is nesseserly, but better be sure
for ($i = 0; $i < 7; $i++) {
for ($j = $i + 1; $j <= 7; $j++) {
$buffer = array(); //this is nesseserly
for ($k = 0; $k < 7; $k++) {
if ($k == $i || $k == $j) {
continue;
}
$buffer[] = $array[$k]; //add to end
}
$result[] = $buffer; //add to end
}
}
var_dump($result);
This works wine for me, tested.
Use array_merge()
http://php.net/manual/en/function.array-merge.php
$a = array("a", "b", "c");
$b = array("g", "a", "f");
$c = array_merge($a, $b);
var_dump($c); //array("a", "b", "c", "g", "a", "f");
I have an array like the following:
array('category_name:', 'c1', 'types:', 't1')
I want the alternate values of an array to be the values of an array:
array('category_name:' => 'c1', 'types:' => 't1')
You could try: (untested)
$data = Array("category_name:","c1","types:","t1"); //your data goes here
for($i=0, $output = Array(), $max=sizeof($data); $i<$max; $i+=2) {
$key = $data[$i];
$value = $data[$i+1];
$output[$key] = $value;
}
Alternatively: (untested)
$output = Array();
foreach($data as $key => $value):
if($key % 2 > 0) { //every second item
$index = $data[$key-1];
$output[$index] = $value;
}
endforeach;
function fold($a) {
return $a
? array(array_shift($a) => array_shift($a))
+ fold($a)
: array();
}
print_r(fold(range('a','p' )));
~)
upd: a real-life version
function fold2($a) {
$r = array();
for($n = 1; $n < count($a); $n += 2)
$r[$a[$n - 1]] = $a[$n];
return $r;
}
Here is another yet complex solution:
$keys = array_intersect_key($arr, array_flip(range(0, count($arr)-1, 2)));
$values = array_intersect_key($arr, array_flip(range(1, count($arr)-1, 2)));
$arr = array_combine($keys, $values);
$array = your array;
$newArray['category_name:'] = $array[1];
$newArray['types:'] = $array[3];