First, i created an array of, let`s say, 6 elements. Then i randomly pick 4 elements that are GOOD (on random position i mean).
Now, i want to randomly pick 2 out of those 4 selected that are VERY GOOD.
If the value of array1 is the same with array2, then i want it to say VERY GOOD. Else, say GOOD. If the value is 0, then BAD.
I tried allpossibilities and all failed.
This is my last attempt of doing so...
$array1 = array();
$array2 = array();
while (count($array1) < 4) {
$rand = rand(1,6);
if (!isset($array1[$rand])) {
$array1[$rand] = TRUE;
}
}
while (count($array2) < 2) {
$rand = rand(1,4);
if (!isset($array2[$rand])) {
$array2[$rand] = TRUE;
}
}
$array2 = $array2 + array_fill(1, 4, FALSE);
$array1 = $array1 + array_fill(1, 6, FALSE);
ksort($array1);
ksort($array2);
foreach($array1 as $k => $v){
if ($v != 0)
{echo "GOOD<br>";}
else {echo "BAD<br>";}}
foreach($array2 as $kc => $vc){
if ($v2 !=0)
{echo "VERY GOOD<br>";}
else {echo "BAD<br>";}}
This is what it gives me:
GOOD
GOOD
BAD
GOOD
GOOD
BAD
VERY GOOD
BAD
BAD
VERY GOOD
As you can see, it gave me 4/6 GOODS and then 2/6 VERY GOODS.
What i wanted was 4/6 GOODS and from those 4 selected i want 2/4 VERY GOODS.
How can i do this?
Thanks in advance,
Vlad
You want one array of size 6 so why are you creating multiple? You can either merge them in some fashion or use the first in construction of the second.
But first, I want to point out that the while() loops are very similar, so it should be easy to put that into a function and save some code to write and have a codebase that is better manageable, as you only need to edit one place to have immediate effect instead of many.
Now for the first task, all you need is the $number of elements to be created and the $range. This function will do what one of your while() loops did plus the array_fill(). (demo)
function fillRandom($range, $num = 1) {
$data = array_fill($range[0], $range[1]+1, FALSE);
for ($i=0; $i<$num; $i++) {
do {
$key = mt_rand($range[0], $range[1]);
} while ($data[$key] === TRUE);
$data[$key] = TRUE;
}
return $data;
}
Now comes the more advanced part: In the second run, we can identify 2 out of the 4 TRUE in the array of 6 elements by giving them another $value (as an example).
The $data will be needed in some cases and by using an $anonymous function we can allow the condition for the while() to be passed.
function fillRandom($range, $num = 1, $value = TRUE, $data = array(), $anon = NULL) {
if (empty($data))
$data = array_fill($range[0], $range[1]+1, FALSE);
if ($anon === NULL) {
$anon = function($el) use($value) {
return $el !== $value;
};
}
for ($i=0; $i<$num; $i++) {
do {
$key = mt_rand($range[0], $range[1]);
} while (isSet($data[$key]) && !$anon($data[$key]));
$data[$key] = $value;
}
return $data;
}
You can then do something like this (demo)
$input = fillRandom(array(0, 5), 4);
ksort($input);
print_r($input);
$input = fillRandom(array(0, 5), 2, 2, $input, function($el){
return $el === TRUE;
});
ksort($input);
print_r($input);
Related
Does anyone know a resource (manual or book) or have the PHP solution for getting all the combinations of x distinct items in y distinct bins?
For example, if I had 2 items [1, 2] with 2 bins, the 4 possibilities would be:
[ 1,2 ] [ ]
[ 1 ] [ 2 ]
[ 2 ] [ 1 ]
[ ] [ 1,2 ]
I need the combinations, not permutations, as order of items is irelevent. And there is no min/max for items in a bin. And if you're going to downgrade my question because it's unclear, please specify what you're confused with. I've spent the entire day trying to find a solution, even in another programming language. Apparently, not very easy to come up with.
UPDATE: Hi Karol, thanks for the comment and link. I'm still working away on this, and did find that page in my searches and converted that to PHP here:
function combinationsOf($k, $xs){
if ($k === 0)
return array(array());
if (count($xs) === 0)
return array();
$x = $xs[0];
$xs1 = array_slice($xs,1,count($xs)-1);
$res1 = combinationsOf($k-1,$xs1);
for ($i = 0; $i < count($res1); $i++) {
array_splice($res1[$i], 0, 0, $x);
}
$res2 = combinationsOf($k,$xs1);
return array_merge($res1, $res2); }
I'm going about it in a different way with this than what I originally hoped for, so still hoping to hear from someone ... thanks!
UPDATE: So I'm making progress, making use of the above recursive function along with another link I found: Permutation Of Multidimensional Array in PHP
Although, correct me if I'm wrong (it's been a loooong day), but it's not permutations, but combinations, that's being generated here.
You could use a backtracking method which utilizes recursion. Basically, it's like a "smart brutforce" approach which takes a path and tries to get combinations which work.
The solution may look a little large but most of the functions are there just to support the combo function. The main brains behind the algorithm is behind the combo function which creates the combinations. The rest of the functions are there to support the combo function and print a nice looking output.
<?php
function toPlainArray($arr2) {
$output = "[";
foreach($arr2 as $arr) {
$output .= "[";
foreach($arr as $val) {
$output .= $val . ", ";
}
if($arr != []) {
$output = substr($output, 0, -2) . "], ";
} else {
$output .= "], ";
}
}
return substr($output, 0, -2) . "]";
}
function difference($arr2d, $arr1d) {
foreach((array)$arr2d as $arr) {
foreach($arr as $item) {
if(in_array($item, $arr1d)) {
$index = array_search($item, $arr1d);
unset($arr1d[$index]);
}
}
}
return $arr1d;
}
function getNextPossibleSol($pSol, $item) { // returns an array (1d)
$allItems = range(1, $item);
return difference($pSol, $allItems);
}
function createEmpty2dArray($arr, $amount) {
for($i = 0; $i < $amount; $i++) {
$arr[] = [];
}
return $arr;
}
function isSmallerThenPartialItems($item, $pSol) {
foreach($pSol as $arr) {
foreach($arr as $val) {
if($val > $item) return false;
}
}
return true;
}
function combo($items, $buckets, $partialSol=[]) {
if($partialSol == []) { // Starting empty array, populate empty array with other arrays (ie create empty buckets to fill)
$partialSol = createEmpty2dArray($partialSol, $buckets);
}
$nextPossibleSol = getNextPossibleSol($partialSol, $items);
if($nextPossibleSol == []) { // base case: solution found
echo toPlainArray($partialSol); // 2d array
echo "<br /><br />";
} else {
foreach($nextPossibleSol as $item) {
for($i = 0; $i < count($partialSol); $i++) {
if(isSmallerThenPartialItems($item, $partialSol)) { // as order doesn't matter, we can use this if-statement to remove duplicates
$partialSol[$i][] = $item;
combo($items, $buckets, $partialSol);
array_pop($partialSol[$i]);
}
}
}
}
}
combo(2, 2); // call the combinations functions with 2 items and 2 buckets
?>
Output:
[[1, 2], []]
[[1], [2]]
[[2], [1]]
[[], [1, 2]]
I am trying to manually sort a PHP array without making use of ksort.
This is how my code looks at the moment:
function my_ksort(&$arg){
foreach($arg as $key1 => $value1){
foreach($arg as $key2 => $value2){
if($key1 > $key2){
$aux = $value2;
$arg[$key2] = $value1;
$arg[$key1] = $aux;
}
}
}
}
It doesn't sort, I can't figure out how to make it sort.
You could try this:
function my_ksort(&$arg)
{
$keys=array_keys($arg);
sort($keys);
foreach($keys as $key)
{
$val=$arg[$key];
unset($arg[$key]);
$arg[$key]=$val;
}
}
I'm sorting the keys separately and then deleting the elements one-by-one and appending them to the end, in ascending order.
I'm using another sorting function (sort()), but if you want to eliminate all available sorting functions from your emulation, sort() is much easier to emulate. In fact, #crypticous's algorithm does just that!
This function return array in ASC. Take in consideration that I'm using goto which is supported in (PHP 5 >= 5.3.0)
function ascending_array($array){
if (!is_array($array)){
$array = explode(",", $array);
}
$new = array();
$flag = true;
iter:
$array = array_values($array); // recount array values with new offsets
(isset($min["max"])) ? $min["value"] = $min["max"] : $min["value"] = $array[0];
$min["offset"] = 0;
for ($i=0;$i<count($array);$i++){
if ($array[$i] < $min["value"]){ // redefine min values each time if statement executed
$min["value"] = $array[$i];
$min["offset"] = $i;
}
if ($flag){ // execute only first time
if ($array[$i] > $min["value"]){ // define max value from array
$min["max"] = $array[$i];
}
$flag = false;
}
if ($i === (count($array)-1)){ // last array element
array_push($new,$min["value"]);
unset($array[$min["offset"]]);
}
}
if (count($array)!=0){
goto iter;
}
print_r($new);
}
$arr = array(50,25,98,45);
ascending_array($arr); // 25 45 50 98
PS. When I was studying php, I wrote this function and now remembered that I had it (that's why I really don't remember what I am doing in it, though fact is it's working properly and hopefully there are comments too), hope you'll enjoy :)
DEMO
I was checking some issue related to this post and i wanted to give my insight about it ! here's what i would have done to implement php's sort :
$array_res = array();
$array = array(50,25,98,45);
$i=0;
$temp = $array[0];
$key = array_search($temp, $array);
while ($i<count($array)-1){
$temp = $array[0];
for($n=0;$n<count($array) ;$n++)
{
if($array[$n]< $temp && $array[$n] != -1 )
{
$temp = $array[$n];
}
else{continue;}
}
//get the index for later deletion
$key = array_search($temp, $array);
array_push($array_res, $temp);
/// flag on those which were ordered
$array[$key] =-1;
$i++;
}
// lastly append the highest number
for($n=0;$n<count($array) ;$n++)
{
if ($array[$n] != -1)
array_push($array_res, $array[$n]);
}
// display the results
print_r($array_res);
This code will display : Array
(
[0] => 25
[1] => 45
[2] => 50
[3] => 98
)
Short and sweet
function custom_ksort($arg)
{
$keys = array_keys($arg);
sort($keys);
foreach($keys as $newV)
{
$newArr[$newV] = $arg[$newV];
}
return $newArr;
}
It looks like your issue is that you're changing "temporary" characters $key1 and $key2 but not the actual arrays. You have to change $arg, not just $key1 and $key2.
Try something like:
$arr = Array(3=>"a",7=>"b");
print_r( $arr );
foreach( $arr as $k=>$v ){
unset($arr[$k]);
$arr[$k+1] = $v;
}
print_r($arr);
I want to generate all possible combination of array elements to fill a placeholder, the placeholder size could vary.
Let say I have array $a = array(3, 2, 9, 7) and placeholder size is 6. I want to generate something like the following:
3,3,3,3,3,3
2,3,3,3,3,3
2,2,3,3,3,3
...........
...........
7,7,7,7,7,9
7,7,7,7,7,7
However (2,3,3,3,3,3) would be considered the same as (3,2,3,3,3,3) so the later one doesn't count.
Could anyone point me to the right direction? I know there is Math_Combinatorics pear package, but that one is only applicable to placeholder size <= count($a).
Edit
I am thinking that this one is similar to bits string combination though with different number base
I have no PHP source code for you but some sources that might help.
Some C code. Look at 2.1:
http://www.aconnect.de/friends/editions/computer/combinatoricode_g.html
Delphi code: combination without repetition of N elements without use for..to..do
Wiki article here
Well it took quit some time to figure this one out.
So i split the question into multiple parts
1.
I firsrt made an array with all the possible value options.
function create_all_array($placeholder, array $values)
{
if ($placeholder <= 0) {
return [];
}
$stack = [];
$values = array_unique($values);
foreach ($values as $value) {
$stack[] = [
'first' => $value,
'childs' => create_all_array($placeholder - 1, $values)
];
}
return $stack;
}
2.
Then I made a function to stransform this massive amount of data into string (no check for uniques).
function string($values, $prefix = '')
{
$stack = [];
foreach($values as $value) {
$sub_prefix = $prefix . $value['first'];
if (empty($value['childs'])) {
$stack[$sub_prefix] = (int)$sub_prefix;
} else {
$stack = array_merge($stack, string($value['childs'], $sub_prefix));
}
}
return $stack;
}
3.
Then the hard part came. Check for duplicates. This was harder than expected, but found some good anser to it and refactored it for my use.
function has_duplicate($string, $items)
{
$explode = str_split ($string);
foreach($items as $item) {
$item_explode = str_split($item);
sort($explode);
$string = implode('',$explode);
sort($item_explode);
$item = implode($item_explode);
if ($string == $item) {
return true;
}
}
return false;
}
4.
The last step was to combine the intel into a new funciton :P
function unique_string($placeholder, array $values)
{
$stack = string(create_all_array($placeholder, $values));
$check_stack = [];
foreach($stack as $key => $item) {
if (has_duplicate($item, $check_stack)) {
unset($stack[$key]);
}
$check_stack[] = $item;
}
return $stack;
}
Now you can use it simple as followed
unique_string(3 /* amount of dept */, [1,2,3] /* keys */);
Ps the code is based for PHP5.4+, to convert to lower you need to change the [] to array() but I love the new syntax so sorry :P
I have an array like this:
[0] = 2
[1] = 8
[2] = 7
[3] = 7
And I want to end up with an array that looks like:
[0] = 7
[1] = 7
Basically, remove all elements where they occur less than twice.
Is their a PHP function that can do this?
try this,
$ar1=array(2,3,4,7,7);
$ar2=array();
foreach (array_count_values($ar1) as $k => $v) {
if ($v > 1) {
for($i=0;$i<$v;$i++)
{
$ar2[] = $k;
}
}
}
print_r($ar2);
output
Array ( [0] => 7 [1] => 7 )
Something like this would work, although you could probably improve it with array_reduce and an anonymous function
<?php
$originalArray = array(2, 8, 7, 7);
foreach (array_count_values($originalArray) as $k => $v) {
if ($v < 2) {
$originalKey = array_search($k, $originalArray);
unset($originalArray[$originalKey]);
}
}
var_dump(array_values($originalArray));
$testData = array(2,8,7,7,5,6,6,6,9,1);
$newArray = array();
array_walk(
array_filter(
array_count_values($testData),
function ($value) {
return ($value > 1);
}
),
function($counter, $key) use (&$newArray) {
$newArray = array_merge($newArray,array_fill(0,$counter,$key));
}
);
var_dump($newArray);
Though it'll give a strict standards warning. To avoid that, you'd need an interim stage:
$testData = array(2,8,7,7,5,6,6,6,9,1);
$newArray = array();
$interim = array_filter(
array_count_values($testData),
function ($value) {
return ($value > 1);
}
);
array_walk(
$interim,
function($counter, $key) use (&$newArray) {
$newArray = array_merge($newArray,array_fill(0,$counter,$key));
}
);
var_dump($newArray);
You could use a combination of array_count_values (which will give you an associative array with the value as the key, and the times it occurs as the value), followed by a simple loop, as follows:
$frequency = array_count_values($yourArray);
foreach ($yourArray as $k => $v) {
if (!empty($frequency[$v]) && $frequency[$v] < 2) {
unset($yourArray[$k]);
}
}
I did not test it, but I reckon it works out of the box. Please note that you will loop over your results twice and not N^2 times, unlike an array_search method. This can be further improved, and this is left as an exercise for the reader.
This was actually harder to do than i thought...anyway...
$input = array(2, 8, 7, 7, 9, 9, 10, 10);
$output = array();
foreach(array_count_values($input) as $key => $value) {
if ($value > 1) $output = array_merge($output, array_fill(0, $value, $key));
}
var_dump($output);
$arrMultipleValues = array('2','3','5','7','7','8','2','9','11','4','2','5','6','1');
function array_not_unique($input)
{
$duplicatesValues = array();
foreach ($input as $k => $v)
{
if($v>1)
{
$arrayIndex=count($duplicatesValues);
array_push($duplicatesValues,array_fill($arrayIndex, $v, $k));
}
}
return $duplicatesValues;
}
$countMultipleValue = array_count_values($arrMultipleValues);
print_r(array_not_unique($countMultipleValue));
Is their [sic!] a PHP function that can do this?
No, PHP has no built-in function (yet) that can do this out of the box.
That means, if you are looking for a function that does this, it needs to be in PHP userland. I would like to quote a comment under your question which already suggest you how you can do that if you are looking for that instead:
array_count_values() followed by a filter with the count >1 followed by an array_fill() might work
By Mark Baker 5 mins ago
If this sounds a bit cryptic to you, those functions he names are actually built-in function in PHP, so I assume this comes most close to the no, but answer:
array_count_values()
array_fill()
This does the job, maybe not the most efficient way. I'm new to PHP myself :)
<?php
$element = array();
$element[0] = 2;
$element[1] = 8;
$element[2] = 7;
$element[3] = 7;
$count = array_count_values($element);
var_dump($element);
var_dump($count);
$it = new RecursiveIteratorIterator( new RecursiveArrayIterator($count));
$result = array();
foreach ($it as $key=>$val){
if ($val >= 2){
for($i = 1; $i <= $val; $i++){
array_push($result,$key);
}
}
}
var_dump($result);
?>
EDIT: var_dump is just so you can see what's going on at each stage
What is the most efficient way to check if an array is a flat array
of primitive values or if it is a multidimensional array?
Is there any way to do this without actually looping through an
array and running is_array() on each of its elements?
Use count() twice; one time in default mode and one time in recursive mode. If the values match, the array is not multidimensional, as a multidimensional array would have a higher recursive count.
if (count($array) == count($array, COUNT_RECURSIVE))
{
echo 'array is not multidimensional';
}
else
{
echo 'array is multidimensional';
}
This option second value mode was added in PHP 4.2.0. From the PHP Docs:
If the optional mode parameter is set to COUNT_RECURSIVE (or 1), count() will recursively count the array. This is particularly useful for counting all the elements of a multidimensional array. count() does not detect infinite recursion.
However this method does not detect array(array()).
The short answer is no you can't do it without at least looping implicitly if the 'second dimension' could be anywhere. If it has to be in the first item, you'd just do
is_array($arr[0]);
But, the most efficient general way I could find is to use a foreach loop on the array, shortcircuiting whenever a hit is found (at least the implicit loop is better than the straight for()):
$ more multi.php
<?php
$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');
$c = array(1 => 'a',2 => 'b','foo' => array(1,array(2)));
function is_multi($a) {
$rv = array_filter($a,'is_array');
if(count($rv)>0) return true;
return false;
}
function is_multi2($a) {
foreach ($a as $v) {
if (is_array($v)) return true;
}
return false;
}
function is_multi3($a) {
$c = count($a);
for ($i=0;$i<$c;$i++) {
if (is_array($a[$i])) return true;
}
return false;
}
$iters = 500000;
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi($a);
is_multi($b);
is_multi($c);
}
$end = microtime(true);
echo "is_multi took ".($end-$time)." seconds in $iters times\n";
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi2($a);
is_multi2($b);
is_multi2($c);
}
$end = microtime(true);
echo "is_multi2 took ".($end-$time)." seconds in $iters times\n";
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi3($a);
is_multi3($b);
is_multi3($c);
}
$end = microtime(true);
echo "is_multi3 took ".($end-$time)." seconds in $iters times\n";
?>
$ php multi.php
is_multi took 7.53565130424 seconds in 500000 times
is_multi2 took 4.56964588165 seconds in 500000 times
is_multi3 took 9.01706600189 seconds in 500000 times
Implicit looping, but we can't shortcircuit as soon as a match is found...
$ more multi.php
<?php
$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');
function is_multi($a) {
$rv = array_filter($a,'is_array');
if(count($rv)>0) return true;
return false;
}
var_dump(is_multi($a));
var_dump(is_multi($b));
?>
$ php multi.php
bool(true)
bool(false)
For PHP 4.2.0 or newer:
function is_multi($array) {
return (count($array) != count($array, 1));
}
I think this is the most straight forward way and it's state-of-the-art:
function is_multidimensional(array $array) {
return count($array) !== count($array, COUNT_RECURSIVE);
}
After PHP 7 you could simply do:
public function is_multi(array $array):bool
{
return is_array($array[array_key_first($array)]);
}
You could look check is_array() on the first element, under the assumption that if the first element of an array is an array, then the rest of them are too.
I think you will find that this function is the simplest, most efficient, and fastest way.
function isMultiArray($a){
foreach($a as $v) if(is_array($v)) return TRUE;
return FALSE;
}
You can test it like this:
$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');
echo isMultiArray($a) ? 'is multi':'is not multi';
echo '<br />';
echo isMultiArray($b) ? 'is multi':'is not multi';
Don't use COUNT_RECURSIVE
click this site for know why
use rsort and then use isset
function is_multi_array( $arr ) {
rsort( $arr );
return isset( $arr[0] ) && is_array( $arr[0] );
}
//Usage
var_dump( is_multi_array( $some_array ) );
Even this works
is_array(current($array));
If false its a single dimension array if true its a multi dimension array.
current will give you the first element of your array and check if the first element is an array or not by is_array function.
You can also do a simple check like this:
$array = array('yo'=>'dream', 'mydear'=> array('anotherYo'=>'dream'));
$array1 = array('yo'=>'dream', 'mydear'=> 'not_array');
function is_multi_dimensional($array){
$flag = 0;
while(list($k,$value)=each($array)){
if(is_array($value))
$flag = 1;
}
return $flag;
}
echo is_multi_dimensional($array); // returns 1
echo is_multi_dimensional($array1); // returns 0
I think this one is classy (props to another user I don't know his username):
static public function isMulti($array)
{
$result = array_unique(array_map("gettype",$array));
return count($result) == 1 && array_shift($result) == "array";
}
In my case. I stuck in vary strange condition.
1st case = array("data"=> "name");
2nd case = array("data"=> array("name"=>"username","fname"=>"fname"));
But if data has array instead of value then sizeof() or count() function not work for this condition. Then i create custom function to check.
If first index of array have value then it return "only value"
But if index have array instead of value then it return "has array"
I use this way
function is_multi($a) {
foreach ($a as $v) {
if (is_array($v))
{
return "has array";
break;
}
break;
}
return 'only value';
}
Special thanks to Vinko Vrsalovic
Its as simple as
$isMulti = !empty(array_filter($array, function($e) {
return is_array($e);
}));
This function will return int number of array dimensions (stolen from here).
function countdim($array)
{
if (is_array(reset($array)))
$return = countdim(reset($array)) + 1;
else
$return = 1;
return $return;
}
Try as follows
if (count($arrayList) != count($arrayList, COUNT_RECURSIVE))
{
echo 'arrayList is multidimensional';
}else{
echo 'arrayList is no multidimensional';
}
$is_multi_array = array_reduce(array_keys($arr), function ($carry, $key) use ($arr) { return $carry && is_array($arr[$key]); }, true);
Here is a nice one liner. It iterates over every key to check if the value at that key is an array. This will ensure true