PHP All possible combinations from a x deep array - php

I have an array:
array(
'ten' => array(
0, => array('four', 'five', 'six'),
1, => array('seventy', 'fourty', 'thirty')
),
'twenty' => array(
0, => array('four', 'five', 'six'),
1, => array('seventy', 'fourty', 'thirty')
),
'thirty' => array(
0, => array('four', 'five', 'six'),
1, => array('seventy', 'fourty', 'thirty')
)
)
i would like to be able to come up with all unique 'leveled' combinations, so in this example i would end up with the following combinations
ten,four,seventy
ten,four,fourty
ten,four,thirty
ten,five,seventy
ten,five,fourty
ten,five,thirty
ten,six,seventy
ten,six,fourty
ten,six,thirty
enz. for the twenty and thirty "first keys".
i have tried to write some recursive loop, using for loops, while loops, and combined, but cant really figure it out, what i know is that there will always be a first level keyd "first number", so that will always be the first number in any combination, then the sublevels will be the same for each "First number", but the amount of children, and the amount of it's children are dynamic...

Related

Merge Two Arrays to Have an Integer Value be an near equal as possible

Application to Distribute Stock between Warehouses
I have two arrays,
One has list of Warehouses along with the Current Quantity: (This can be Dynamic with one or more locations)
[
['location_name' => 'Toronto', 'current_qty' => 3],
['location_name' => 'Mississauga','current_qty' => 7],
['location_name' => 'London', 'current_qty' => 5],
]
The Other array has the Amount of Stock that would be Comming in:
[
'qty' => 5
]
And want to distribute the Qty among the locations so that the current qty of each of the locations would be near equal to each other. So want to return an array with the number that needs to be added to each location. Like: Here , of the 5, 3 went to Toronto and 2 to London. So it can be seen then after the nearest equalization, rest of the distribution can be done randomly.
[
['location_name' => 'Toronto', 'add_qty' => 3],
['location_name' => 'Mississauga','add_qty' => 0],
['location_name' => 'London', 'add_qty' => 2],
]
And Just cannot figure out the logic of this algorithm. Would really appreciate any pointers. Many Thanks.
I would do it like this, not really sure about any performance issues. I don't know how big your data set is.
$locations = [
['location_name' => 'Toronto', 'current_qty' => 3, 'add_qty' => 0],
['location_name' => 'Mississauga', 'current_qty' => 7, 'add_qty' => 0],
['location_name' => 'London', 'current_qty' => 5, 'add_qty' => 0],
];
$supplies = 5;
// This function sorts locations, by comparing the sum of the current quantity and the quantity the location will get.
$locationsByQuantityAscending = function ($locationA, $locationB) {
return ($locationA['current_qty'] + $locationA['add_qty']) - ($locationB['current_qty'] + $locationB['add_qty']);
};
// Sort the locations, getting the ones with the lowest quantity first.
usort($locations, $locationsByQuantityAscending);
// Keep dividing, until we're out of supplies
while ($supplies > 0) {
$locations[0]['add_qty']++; // Add one to the location with the lowest supplies
$supplies--; // Decrease the supplies by one
usort($locations, $locationsByQuantityAscending); // Sort the locations again.
}
print_r($locations);
At the end, this will output:
Array
(
[0] => Array
(
[location_name] => Toronto
[current_qty] => 3
[add_qty] => 3
)
[1] => Array
(
[location_name] => London
[current_qty] => 5
[add_qty] => 2
)
[2] => Array
(
[location_name] => Mississauga
[current_qty] => 7
[add_qty] => 0
)
)
If you really need to be performant, you could also just sort the locations once by their current quantity. Then keep adding to the first location, until its stock will be higher than the second location. Then, until the quantity at the second location is higher than the third location, add one to the first and second location, etc.
I think this will be more performant, since you don't have to sort all your locations X times (X being the number of supplies to divide). I'll leave that implementation to you.
Hint: have a look at recursive functions
If performance is critical, and the input data is usually bigger then shown here (e.g. a lot more locations or a lot more quantity to distribute). You might want to consider using SplMinHeap:
For example:
<?php
$helper = new class extends SplMinHeap
{
public function compare($a, $b): int
{
return ($b['current_qty'] + $b['add_qty']) <=> ($a['current_qty'] + $a['add_qty']);
}
};
$locations = [
['location_name' => 'Toronto', 'current_qty' => 3, 'add_qty' => 0],
['location_name' => 'Mississauga', 'current_qty' => 7, 'add_qty' => 0],
['location_name' => 'London', 'current_qty' => 5, 'add_qty' => 0],
];
foreach ($locations as $entry) {
$helper->insert($entry);
}
$qty = 10000;
while ($qty-- > 0) {
$min = $helper->extract();
$min['add_qty']++;
$helper->insert($min);
}
print_r(iterator_to_array($helper));
https://3v4l.org/nDOY8

PHP MongoDB find with multiple "AND" conditions?

After hours of experimentations and readings, I cannot find a solution to this problem:
I want to do a MongoDB->find($query) with multiple AND conditions.
For instance, say I want id = 5 and a < 6 and a > 2 and b > 10 and b < 20
I was expecting $query to be:
$query = array("id" => 5,
"a" => array('$gt' => 2,
'$lt' => 6),
"b" => array('$gt' => 10,
'$lt' => 20))
But this returns empty results with my DB
I tried various syntaxes such as:
$query = array("id" => 5,
array( "a" => array('$gt' => 2,
'$lt' => 6),
"b" => array('$gt' => 10,
'$lt' => 20)))
But this fails too.
Also tried with "$AND" variants, no luck.
Is it possible to "mix" several AND conditions in PHP-MongoDB find() requests?
I've just tested this using MongoDB PHP driver v1.6.11 (PHP-5.5.9). The test data are as below
db.collection.insert({id:5, a:4, b:15})
db.collection.insert({id:9, a:4, b:15})
db.collection.insert({id:5, a:4, b:20})
Using PHP code snippet:
$condition = array(
'$and' => array(
array(
"id" => 5,
"a" => array('$gt' => 2, '$lt' => 6),
"b" => array('$gt' => 10, '$lt' => 20)
)
)
);
$docs = $coll->find($condition);
foreach( $docs as $o=> $doc) {
echo json_encode($doc);
}
The above returns only the first document sample. This indicates that $and should work as expected. I've also tested without $and, i.e. :
$condition = array(
"id" => 5,
"a" => array('$gt' => 2, '$lt' => 6),
"b" => array('$gt' => 10, '$lt' => 20)
);
Which also works the same. Try checking your dataset, whether there is a document matching your criteria.
This issue is closed: bad value types in the DB (string instead of float/double). Works as expected when updating to correct types in DB.

get integer / float from string in PHP

I ran into an issue with a data feed I need to import where for some reason the feed producer has decided to provide data that should clearly be either INT or FLOAT as strings-- like this:
$CASES_SOLD = "THREE";
$CASES_STOCKED = "FOUR";
Is there a way in PHP to interpret the text string as the actual integer?
EDIT: I should be more clear-- I need to have the $cases_sold etc. as an integer-- so I can then manipulate them as digits, store in database as INT, etc.
Use an associative array, for example:
$map = array("ONE" => 1, "TWO" => 2, "THREE" => 3, "FOUR" => 4);
$CASES_SOLD = $map["THREE"]; // 3
If you are only interested by "converting" one to nine, you may use the following code:
$convert = array('one' => 1,
'two' => 2,
'three' => 3,
'four' => 4,
'five' => 5,
'six' => 6,
'seven' => 7,
'eight' => 8,
'nine' => 9
);
echo $convert[strtolower($CASES_SOLD)]; // will display 3
If you only need the base 10 numerals, just make a map
$numberMap = array(
'ONE' => 1
, 'TWO' => 2
, 'THREE' => 3
// etc..
);
$number = $numberMap[$CASES_SOLD];
// $number == 3'
If you need something more complex, like interpreting Four Thousand Two Hundred Fifty Eight into 4258 then you'll need to roll up your sleeves and look at this related question.
Impress your fellow programmers by handling this in a totally obtuse way:
<?php
$text = 'four';
if(ereg("[[.$text.]]", "0123456789", $m)) {
$value = (int) $m[0];
echo $value;
}
?>
You need a list of numbers in english and then replace to string, but, you should play with 'thousand' and 'million' clause where must check if after string 'thousend-three' and remove integer from string.
You should play with this function and try change if-else and add some functionality for good conversion:
I'm writing now a simple code for basic, but you know others what should change, play!
Look at million, thousand and string AND, it should be change if no in string like '1345'. Than replace with str_replace each of them separaterly and join them to integer.
function conv($string)
{
$conv = array(
'ONE' => 1,
'TWO' => 2,
'THREE' => 3,
'FOUR' => 4,
'FIVE' => 5,
'SIX' => 6,
'SEVEN' => 7,
'EIGHT' => 8,
'NINE' => 9,
'TEN' => 10,
'ELEVEN' => 11,
'TWELVE' => 12,
'THIRTEEN' => 13,
'FOURTEEN' => 14,
'FIFTEEN' => 15,
'SIXTEEN' => 16,
'SEVENTEEN' => 17,
'EIGHTEEN' => 18,
'NINETEEN' => 19,
'TWENTY' => 20,
'THIRTY' => 30,
'FORTY' => 40,
'FIFTY' => 50,
'SIXTY' => 60,
'SEVENTY' => 70,
'EIGTHY' => 80,
'NINETY' => 90,
'HUNDRED' => 00,
'AND' => '',
'THOUSAND' => 000
'MILLION' => 000000,
);
if (stristr('-', $string))
{
$val = explode('-', $string);
#hardcode some programming logic for checkers if thousands, should if trim zero or not, check if another values
foreach ($conv as $conv_k => $conv_v)
{
$string[] = str_replace($conv_k, $conv_v, $string);
}
return join($string);
}
else
{
foreach ($conv as $conv_k => $conv_v)
{
$string[] = str_replace($conv_k, $conv_v, $string);
}
return join($string);
}
}
Basically what you want is to write a parser for the formal grammar that represents written numbers (up to some finite upper bound). Depending on how high you need to go, the parser could be as trivial as
$numbers = ('zero', 'one', 'two', 'three');
$input = 'TWO';
$result = array_search(strtolower($input), $numbers);
...or as involved as a full-blown parser generated by a tool as ANTLR. Since you probably only need to process relatively small numbers, the most practical solution might be to manually hand-code a small parser. You can take a look here for the ready-made grammar and implement it in PHP.
This is similar to Converting words to numbers in PHP
PHP doesn't have built in conversion functionality. You'd have to build your own logic based on switch statements or otherwise.
Or use an existing library like:
http://www.phpclasses.org/package/7082-PHP-Convert-a-string-of-English-words-to-numbers.html

Retrieve Child Objects

I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.
This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);
This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8

PHP: How will array depth influence performance?

Now I know there is some related questions on this topic but this is somewhat unique.
I have two array structures :
array(
[0] => array(
'stat1' => 50,
'stat2' => 12,
'stat3' => 0,
'country_name' => 'United States'
),
[1] => array(
'stat1' => 40,
'stat2' => 38,
'stat3' => 15,
'country_name' => 'Ireland'
),
[2] => array(
'stat1' => 108,
'stat2' => 0,
'stat3' => 122,
'country_name' => 'Autralia'
)
)
and the second
array(
'stat1' => array(
'countries' => array(
'United States' => 50,
'Ireland' => 40,
'Autralia' => 108,
)
)
),
'stat2' => array(
'countries' => array(
'United States' => 12,
'Ireland' => 38,
)
)
),
etc...
The second array can go even to level 4 or 5 if you add the cities of those respective countries. Further to note is that the second array structure will have no 0 data fields (note that in the second one australia is not there because it is 0) but the first structure will have a whole whack of zeros. Also note that the second structure will have duplicates i.e. 'United States'
My question is this: How does these array structures compare when they are json_encode() and used in a POST ajax request? Will the shallow depth array, with it's whack of zeros be faster or will the better structured array be better in terms of size?
I have done some testing and for a finite dataset the difference in the output data - (I outputted the data into a text file) between the two is insignificant really.
Array structure 1 - All city and country data outputs to 68kb
Array structure 2 - All city and country data outputs to 71kb
So there is a slight difference but it seems that the difference is insignificantly small when taking into account that the data is in JSON format and used in an AJAX request to the google visualization geomap API.
I haven't tested the micro times in loading difference but for a user to look at a loading .gif image for 0.0024microseconds (i'm shooting a random time for the sake of argument) does not make a big dent in usability either way. Thanx all for you comments

Categories