PHP algorithm big arrays issue with memory - php

I am working on some algorithm in PHP dealing with binary values or strings containing 0s and 1s. I am calculating the list for n-numbers, from starting list 0f {0,1} for n=1;
Anyway, arrays a[] and b[] are becoming big after for n > 20, reaching memory issue. So my question is how this algorithm can be optimized to use less memory? Should i store binary strings in a different format in memory except string format or do I need to restructure the algorithm itself? Any idea?
while ($n < 1 || $n > 65)
fscanf(STDIN, "%d\n", $n);
$listn = array("0","1");
$doublearray[] = $listn;
for ($i=1; $i<$n;$i++) {
foreach ($listn as $member) {
$a[] = "0" . $member;
}
$reflectedlistn = array_reverse($listn);
foreach ($reflectedlistn as $member) {
$b[] = "1" . $member;
}
$listn = array_merge($a, $b);
$doublearray[] = $listn;
$a = array();
$b = array();
}
$arr = array_slice($doublearray[$n-1], -$n);
echo "\n";
foreach ($arr as $item) {
echo $item . "\n";
}

You could optimize your algorithm by storing numbers.
while ($n < 1 || $n > 65)
fscanf(STDIN, "%d\n", $n);
$listn = array(0, 1); // use numbers
$doublearray[] = $listn;
for ($i = 1; $i < $n; $i++) {
foreach ($listn as $member) {
$a[] = 0 + $member; //actually do nothing
}
$reflectedlistn = array_reverse($listn);
foreach ($reflectedlistn as $member) {
$b[] = (1 << $i) + $member; // add 1 to the begining
}
$listn = array_merge($a, $b);
$doublearray[] = $listn;
$a = array();
$b = array();
}
$arr = array_slice($doublearray[$n - 1], -$n);
echo "\n";
foreach ($arr as $item) {
echo decbin($item) . "\n"; // convert dec into bin string representation
}
It saves near 15% of memory.
Then remove useless array $a.
$listn = array(0, 1); // use numbers
$doublearray[] = $listn;
for ($i = 1; $i < $n; $i++) {
$reflectedlistn = array_reverse($listn);
foreach ($reflectedlistn as $member) {
$b[] = (1 << $i) + $member; // add 1 to the begining
}
$listn = array_merge($listn, $b);
$doublearray[] = $listn;
$a = array();
$b = array();
}
$arr = array_slice($doublearray[$n - 1], -$n);
echo "\n";
foreach ($arr as $item) {
echo decbin($item) . "\n"; // convert dec into bin string representation
}
more 20% of memory.
But it won't help, because this algorithm creates arrays with 2^n elements. And arrays are Very Huge in PHP.
So, is there any point to optimize it? Or better create new one? Please, describe what are you want to achieve to get better solution.

Related

How to simplify a nested loops?

I have 2 ranges I am currently looping through.
$arr1 = range(1500, 1505);
$start = 1;
$end = 10;
foreach ($arr1 as $block) {
for ($i = $start; $i <= $end; $i++) {
echo $block . $i; // output -> 15001,15002,15003 ... 15011, 15012 ...
}
}
Is there an easier / more efficient way to do this?
I believe you can do it like this:
for($start = 15001; $start < 15061 ; $start = $start + 10 ) {
$arr = range($start, $start + 8);
$arr[] = $start * 10;
echo implode(" ", $arr) . PHP_EOL;
}
However, I still not get the pattern you trying the create...
Another slightly more efficient approach would be to create the entire range at once. Then use modulo to determine the values divisible by 10, and use mathematics to output the desired alternative value.
Example: https://3v4l.org/L10Jq
foreach (range(15001, 15060) as $v) {
if (0 === $v % 10) {
echo ($v - 9) * 10 . \PHP_EOL;
} else {
echo $v . ' ';
}
}
Result:
15001 15002 15003 15004 15005 15006 15007 15008 15009 150010
15011 15012 15013 15014 15015 15016 15017 15018 15019 150110
15021 15022 15023 15024 15025 15026 15027 15028 15029 150210
15031 15032 15033 15034 15035 15036 15037 15038 15039 150310
15041 15042 15043 15044 15045 15046 15047 15048 15049 150410
15051 15052 15053 15054 15055 15056 15057 15058 15059 150510
To create a single array, pass the value $v by-reference, remove the echo calls and re-assign the value in the conditional.
$ar = range(15001, 15060);
foreach ($ar as &$v) {
if (0 === $v % 10) {
$v = ($v - 9) * 10;
}
}

php random number with number(1-9) only 6 length

I want only 6 random numbers [length = 6] from 0,1,2,3,4,5,6,7,8,9 in php function without duplicates.
This is my code
$a = mt_rand(1,9999999999); //because I need from 1 to 9999999999 of(0,1,2,3,4,5,6,7,8,9)
for ($i = 0; $i<6; $i++)
{
$a .= mt_rand(0,9);
}
I am not sure my code is good solution or not
How I can do it?
Try this code.
function GenerateRandom($min, $max, $range) {
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $range);
}
print_r( GenerateRandom(0,25,6) );
Hope this helps.
If your source array is rather big, you may save some memory by only fetching what you need:
$a = range(0, 9);
for ($i = 0, $n = count($a); $i < 6 && --$n; ++$i) {
$r = mt_rand(0, $n);
if ($r != $n) {
$tmp = $a[$n];
$a[$n] = $a[$r];
$a[$r] = $tmp;
}
}
echo join(',', array_slice($a, -6));
I'm coining the term "Partial Knuth Shuffle" for this.

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]));

Pair the elements in an array by two's then find the difference and sum

Let's say I have this array
$number = [2,1,4,3,6,2];
First pair the elements on an array by two's and find their difference
so this is the output in the first requirement
$diff[] = [1,1,4];
Second sum all the difference
this is the final output
$sum[] = [6];
Conditions:
the array size is always even
the first element in a pair is always greater than the second one, so their is no negative difference
What I've done so far is just counting the size of an array then after that I don't know how to pair them by two's. T_T
Is this possible in php? Is there a built in function to do it?
One line:
$number = [2,1,4,3,6,2];
$total = array_sum(array_map(function ($array) {
return current($array) - next($array);
}, array_chunk($number, 2)));
echo $total;
This should work fine:
<?
$number = array(2,1,4,3,6,2);
for($i=0;$i<count($number); $i+=2){
$dif[] = $number[$i] - $number[$i+1];
}
print_r($dif);
$sum = 0;
foreach ($dif as $item){
$sum += $item;
}
echo 'SUM = '.$sum;
?>
Working CODE
If you want all the different stages kept,
$numbers = [2,1,4,3,6,2];
$diff = [];
for($i=0,$c=count($numbers);$i<$c;$i+=2)
{
$diff[] = $numbers[$i]-$numbers[$i+1];
}
$sum = array_sum($diff);
Else, to just get the total and bypass the diff array:
$numbers = [2,1,4,3,6,2];
$total = 0;
for($i=0,$c=count($numbers);$i<$c;$i+=2)
{
$total += $numbers[$i]-$numbers[$i+1];
}
I have got this far it gives the required solution.
$arr = array(2,1,4,3,6,2);
$temp = 0;
$diff = array();
foreach ($arr as $key => $value) {
if($key % 2 == 0) {
$temp = $value;
}
else {
$diff[] = $temp - $value;
}
}
print_R($diff);
print 'Total :' . array_sum($diff);
Note : Please update if any one knows any pre-defined function than can sorten this code.
Please check and see if this works for you.
<?php
$sum=0;
$number = array(2,1,4,3,6,2);
for ($i=0;$i<=count($number);$i++) {
if ($i%2 == 1 ) {
$sum = $sum + $number[$i-1] - $number[$i];
}
}
print $sum;
?>
Well with your conditions in mind I came to the following
$number = [2,1,4,3,6,2];
$total = 0;
for($i = 0; $i < count($number); $i+=2) {
$total += $number[$i] - $number[$i + 1];
}
Try this one:
$number = array(2,1,4,3,6,2);
$diff = array();
$v3 = 0;
$i=1;
foreach($number as $val){
if ($i % 2 !== 0) {
$v1 = $val;
}
if ($i % 2 === 0) {
$v2 = $val;
$diff[] = $v1-$v2;
$v3+= $v1-$v2;
}
$i++;
}
print $v3;//total value
print_r($diff); //diff value array

Finding 4 highest values from an array

Instead of just 1, how can I pick the 4 highest values from an array using max()?
You could use an SplMaxHeap
function maxN(array $numbers, $n)
{
$maxHeap = new SplMaxHeap;
foreach($numbers as $number) {
$maxHeap->insert($number);
}
return iterator_to_array(
new LimitIterator($maxHeap, 0, $n)
);
}
Usage (demo):
print_r( maxN( array(7,54,2,4,26,7,82,4,34), 4 ) );
You could try this:
$a = array(3,5,6,1,23,6,78,99);
asort($a);
var_dump(array_slice($a, -4));
HTH.
This will do it in Θ(n) time:
$a = $b = $c = $d = null;
foreach($array as $v) {
if(!isset($a) || $v > $a) {
$d = $c;
$c = $b;
$b = $a;
$a = $v;
}elseif(!isset($b) || $v > $b) {
$d = $c;
$c = $b;
$b = $v;
}elseif(!isset($c) || $v > $c) {
$d = $c;
$c = $v;
}elseif(!isset($d) || $v > $d) {
$d = $v;
}
}
$result = array($a, $b, $c, $d);
function maxs($ar, $count=4)
{
$res = array();
foreach ($ar as $v)
{
for ($i = 0;$i < $count;$i++)
{
if ($i >= count($res) || $v > $res[$i])
{
do
{
$tmp = $res[$i];
$res[$i] = $v;
$v = $tmp;
$i++;
}
while ($i < $count);
break;
}
}
}
return $res;
}
A simple method using php predefined functions.
<?php
$arr = array(6, 8, 3, 2, 7, 9);
rsort($arr);
$first = array_shift($arr);
$second = array_shift($arr);
$third = array_shift($arr);
echo $first; // print 9
echo $second; // print 8
echo $third; // print 7
?>
While storing itself you can maintain another array as soon as the new item is inserted check with the max value in the inner array if the item being inserted is greater insert this item. During the item pop do viceversa. From the inner maintained array you can get as many max numbers as possible.

Categories