PHP arrays - unique combinations out of 3 arrays - php

I'm not even sure how to approach the problem so I'm just stating the problem. Any help is highly appreciated.
There's this array ($colors) of all possible values:
$colors = array ('red','blue','green','yellow');
Then there's an array ($boxes) of all the possible values - consisting of equal number of values as $colors:
$boxes = array ('circular','squared','hexagonal','triangular');
There's this third array which defines the constraints in making the unique combination:
$possible_combos = array
(
array('circular','red','blue'),
array('squared','red','green'),
array('hexagonal','blue','yellow'),
array('triangular','red','green')
);
Question: How do I get a new array $result with key=>value combinations just that each box is assigned a unique color out of it's possible sets of colors
So a valid $result array would be:
Array ( [circular] => red
[squared] => blue
[hexagonal]=> yellow
[triangular] => green
)
NOTE: If you traverse sequentially, 'red', 'blue', 'green' might get assigned to first three 'boxes' and there might not be anything to pick for the fourth box (since 'yellow' is not allowed to be assigned to it.
I'm thinking, to process the least occurring 'colors' first but really unsure how to handle it syntactically.
Once again thanks for looking into it, in advance! Even some help with how to approach the problem would be nice.
Following code is not producing the correct output either:
foreach ($colors as $c => $color) {
foreach ($boxes as $b => $box) {
for ($i=0; $i < count($colors) ; $i++) {
if(in_array($possible_combos[$i][1],$colors) && !in_array($possible_combos[$i][1], $result))
{
$result[$box] = $possible_combos[$i][1];
unset($colors[$c]);
break;
}
else if(in_array($possible_combos[$i][2],$colors) && !in_array($possible_combos[$i][2], $result))
{
$result[$box] = $possible_combos[$i][2];
unset($colors[$c]);
break;
}
}
}
}

I'm thinking, to process the least occurring 'colors' first but really unsure how to handle it syntactically.
That's a good intuition considering the fact that you have only one box type that can share one of many colors. Because your constraining resource is color, I think it makes sense to sort your rules by them first and then you can distribute by scarcity.
https://3v4l.org/u5pBK
$colors = array ('red','blue','green','yellow');
$boxes = array ('circular','squared','hexagonal','triangular');
$possible_combos = array
(
array('circular','red','blue'),
array('squared','red','green'),
array('hexagonal','blue','yellow'),
array('triangular','red','green')
);
// collect constraints ordered by rarest
foreach ($possible_combos as $constraint) {
$box = array_shift($constraint);
foreach ($constraint as $color) {
$constraints[$color] []= $box;
}
}
// assign rarest first to last
asort($constraints);
foreach ($constraints as $color => $allowedBoxes) {
foreach ($allowedBoxes as $box) {
$key = array_search($box, $boxes);
// if we have a match, then remove it from the collection
if ($key !== false) {
$result[$box] = $color;
unset($boxes[$key]);
continue 2;
}
}
}
print_r($result);
Array
(
[hexagonal] => yellow
[circular] => blue
[squared] => green
[triangular] => red
)

Related

Multidimensional array keys to variable

sadly i havent found any solution yet.
I have an multidimensional array which looks like this:
Array
(
[0] => Array
(
[Symbol] => CASY.US
[Position] => 169873920
)
[1] => Array
(
[Symbol] => US500
[Position] => 168037428
) )
Now i want to write the name of the keys of the inner array into variables so that i have these variables with the values:
$col1 = "Symbol"
$col2 = "Position"
How can i achieve that? Somehow with a couple of foreach loops?
Background: After that i want to check if the columns have the right name for a validation.
Thanks in advance!
Loop nested and save the keys to an array with "col" and an integer that you later can (if you really must extract), but I recommend to keep them in the array.
foreach($array as $subarray){
$i = 1;
foreach($subarray as $key => $val){
$keys["col" . $i] = $key;
$i++;
}
break; // no need to keep looping if the array is uniform
}
//if you must:
extract($keys);
https://3v4l.org/ALVtp
If the subarrays are not the same then you need to loop all subarrays and see if the key has already been saved, if not save it else skip it.
$keys =[];
$i = 1;
foreach($array as $subarray){
foreach($subarray as $key => $val){
if(!in_array($key, $keys)){
$keys["col" . $i] = $key;
$i++;
}
}
}
var_dump($keys);
//if you must:
extract($keys);
var_dump($col1, $col2, $col3);
https://3v4l.org/EklPK
Honestly I would do something like this:
$required = array_flip(['Symbol', 'Position']); //flip because I am lazy like that ['Symbol'=>0, 'Position'=>1]
foreach($array as $subarray){
$diff = array_diff_key($required, $subarray);
//prints any keys in $required that are not in $subarray
print_r($diff);
if(!empty($diff)){
//some required keys were missed
}
}
While its not clear how you validate these the reason is as I explained in this comment
it still doesn't solve the problem, as you really have no way to know what the keys will be (if they are not uniform). So with my example foo is $col3 what if I have bar later that's $col4 what if the order is different next time.... they will be different numbers. Sure it's a few what if's but you have no guarantees here.
By dynamically numbering the keys, if the structure of the array ever changes you would have no idea what those dynamic variables contain, and as such no idea how to validate them.
So even if you manage to make this work, if your data ever changes you going to have to re-visit the code.
In any case if your wanting to see if each array contains the keys it needs to, what I put above would be a more sane way to do it.

Set value in array PHP

I have an multidimensional array with objects. If the object has status 1 or 2 and the color is not green, I want to set color to blue. How can I do that?
foreach ($objects as $obj) {
if (in_array($obj['status'], [1,2] )) {
if ($obj['color'] != 'green'){
//set color to blue
}
}
}
No need to have nested ifs, just combine them into one condition, and you can reference the copy & to make your changes:
foreach ($objects as &$obj) {
// ^ reference
if (in_array($obj['status'], [1,2]) && $obj['color'] != 'green') {
// set to blue
$obj['color'] = 'blue';
}
}
The answer provided by #Ghost is correct when working with arrays. As arrays are not really objects they must be passed by reference otherwise they are copied. Objects are passed by reference.
This is actually pretty horrible, and one of the (many) reasons you should avoid basic PHP arrays. Additionally, if you make a reference of a reference, you'll likely end up with a memory leak.
If $objects where actually an array of actual objects, you don't need to specify that it should be treated as an exception. Here's a test I wrote (sorry it's a bit ugly):
$objects = array(
(object)array(
'status' => 1,
'color' => 'red',
)
);
foreach ($objects as $obj) {
if (in_array($obj->status, array(1,2)) && $obj->color != 'green') {
// set to blue
$obj->color = 'blue';
}
}
foreach ($objects as $obj) {
echo $obj->color;
}
For the most part, PHP objects are faster and more memory efficient that PHP arrays, and will act very similarly in most cases.

php - Find array for which a key have a given value

I have an array of dictionnaries like:
$arr = array(
array(
'id' => '1',
'name' => 'machin',
),
array(
'id' => '2',
'name' => 'chouette',
),
);
How can I find the name of the array containing the id 2 (chouette) ?
Am I forced to reindex the array ?
Thank you all, aparently I'm forced to loop through the array (what I wanted to avoid), I thought that it were some lookup fonctions like Python. So I think I'll reindex with id.
Just find the index of array that contains the id you want to find.
SO has enough questions and answers on this topic available.
Assuming you have a big array with lots of data in your real application, it might be too slow (for your taste). In this case, you indeed need to modify the structure of your arrays, so you can look it up faster, e.g. by using the id as an index for the name (if you are only interested in the name).
As a for loop would be the best way to do this, I would suggest changing you array so that the id is the arrays index. For example:
$arr = array(
1 => 'machin',
2 => 'chouette',
);
This way you could just get the name for calling $arr[2]. No looping and keeping your program running in linear time.
$name;
foreach ($arr as $value){
if ( $value['id'] == 2 ){
$name = $value['name'];
break;
}
}
I would say that it might be very helpful to reindex the information. If the ID is unique try something like this:
$newarr = array();
for($i = 0;$i < count($arr);$i++){ $newarr[$arr[$i]['id']] = $arr[$i]['name']; }
The result would be:
$newarr = array('1'=>'machin','2'=>'chouette');
Then you can go trough the array with "foreach" like this:
foreach($newarr as $key => $value){
if($value == "machin"){
return $key;
}
}
But of course the same would work with your old array:
foreach($arr as $item){
if($item['name'] == "machin"){
return $item['id'];
}
}
It depends on what you are planning to do with the array ;-)
array_key_exist() is the function to check for keys. foreach will help you get down in the multidimensional array. This function will help you get the name element of an array and let you specify a different id value.
function findKey($bigArray, $idxVal) {
foreach($bigArray as $array) {
if(array_key_exists('id', $array) && $array['id'] == $idxVal) {
return $array['name'];
}
}
return false;
}
//Supply your array for $arr
print(findKey($arr, '2')); //"chouette"
It's a bit crude, but this would get you the name...
$name = false;
foreach($arr as $v) {
if($v['id'] == '2') {
$name = $v['name'];
break;
}
}
echo $name;
So no, you are not forced to reindex the array, but it would make things easier.

PHP - How to append array with some conditions

$list = array(
[0]=> array(
[name]=>'James'
[group]=>''
)
[1]=> array(
[name]=>'Bobby'
[group]=>''
)
)
I am looking to update the item 'group' where the name is 'Bobby'. I am looking for a solution with the two following formats. Thank you in advance for your replies. Cheers. Marc.
array_push($list, ???)
and
$list[] ??? = someting
As far as I know, there's no way updating your array with one of the given syntax.
The only similar thing I can come on is looping over the array using array_walk ... http://www.php.net/manual/en/function.array-walk.php
Example:
array_walk($list, function($val, $key) use(&$list){
if ($val['name'] == 'Bobby') {
// If you'd use $val['group'] here you'd just editing a copy :)
$list[$key]['group'] = "someting";
}
});
EDIT: Example is using anonymous functions which is only possible since PHP 5.3. Documentation offers also ways working with older PHP-versions.
This code may help you:
$listSize = count($list);
for( $i = 0; $i < $listSize; ++$i ) {
if( $list[$i]['name'] == 'Bobby' ) {
$list[$i]['group'] = 'Hai';
}
}
array_push() doesn't really relate to updating a value, it only adds another value to an array.
You cannot have a solution that will fit both formats. The implicit array push $var[] is a syntactic construct, and you cannot invent new ones - certainly not in PHP, and not most (all?) other languages either.
Aside from that, what you are doing is not pushing an item on to the array. For one thing, pushing items implies an indexed array (yours is associative), and for another pushing implies adding a key to the array (the key you want to update already exists).
You can write a function to do it, something like this:
function array_update(&$array, $newData, $where = array(), $strict = FALSE) {
// Check input vars are arrays
if (!is_array($array) || !is_array($newData) || !is_array($where)) return FALSE;
$updated = 0;
foreach ($array as &$item) { // Loop main array
foreach ($where as $key => $val) { // Loop condition array and compare with current item
if (!isset($item[$key]) || (!$strict && $item[$key] != $val) || ($strict && $item[$key] !== $val)) {
continue 2; // if item is not a match, skip to the next one
}
}
// If we get this far, item should be updated
$item = array_merge($item, $newData);
$updated++;
}
return $updated;
}
// Usage
$newData = array(
'group' => '???'
);
$where = array(
'name' => 'Bobby'
);
array_update($list, $newData, $where);
// Input $array and $newData array are required, $where array can be omitted to
// update all items in $array. Supply TRUE to the forth argument to force strict
// typed comparisons when looking for item(s) to update. Multiple keys can be
// supplied in $where to match more than one condition.
// Returns the number of items in the input array that were modified, or FALSE on error.

Checking if all the array items are empty PHP

I'm adding an array of items from a form and if all of them are empty, I want to perform some validation and add to an error string. So I have:
$array = array(
'RequestID' => $_POST["RequestID"],
'ClientName' => $_POST["ClientName"],
'Username' => $_POST["Username"],
'RequestAssignee' => $_POST["RequestAssignee"],
'Status' => $_POST["Status"],
'Priority' => $_POST["Priority"]
);
And then if all of the array elements are empty perform:
$error_str .= '<li>Please enter a value into at least one of the fields regarding the request you are searching for.</li>';
You can just use the built in array_filter
If no callback is supplied, all entries of input equal to FALSE (see converting to boolean) will be removed.
So can do this in one simple line.
if(!array_filter($array)) {
echo '<li>Please enter a value into at least one of the fields regarding the request you are searching for.</li>';
}
Implode the array with an empty glue and check the size of the resulting string:
<?php if (strlen(implode($array)) == 0) echo 'all values of $array are empty'; ?>
Please note this is a safe way to consider values like 0 or "0" as not empty. The accepted answer using an empty array_filter callback will consider such values empty, as it uses the empty() function. Many form usages would have to consider 0 as valid answers so be careful when choosing which method works best for you.
An older question but thought I'd pop in my solution as it hasn't been listed above.
function isArrayEmpty(array $array): bool {
foreach($array as $key => $val) {
if ($val !== '' || $val !== null) // remove null check if you only want to check for empty strings
return false;
}
return true;
}
you don't really need it.
You're going to validate these fields separately and by finishing this process you can tell if array was empty (or contains invalid values, which is the same)
simplify use this way:
$array = []; //target array
$is_empty = true; //flag
foreach ($array as $key => $value) {
if ($value != '')
$is_empty = false;
}
if ($is_empty)
echo 'array is empty!';
else
echo 'array is not empty!';
I had the same question but wanted to check each element in the array separately to see which one was empty. This was harder than expected as you need to create the key values and the actual values in separate arrays to check and respond to the empty array element.
print_r($requestDecoded);
$arrayValues = array_values($requestDecoded); //Create array of values
$arrayKeys = array_keys($requestDecoded); //Create array of keys to count
$count = count($arrayKeys);
for($i = 0; $i < $count; $i++){
if ( empty ($arrayValues[$i] ) ) { //Check which value is empty
echo $arrayKeys[$i]. " can't be empty.\r\n";
}
}
Result:
Array
(
[PONumber] => F12345
[CompanyName] => Test
[CompanyNum] => 222222
[ProductName] => Test
[Quantity] =>
[Manufacturer] => Test
)
Quantity can't be empty.
this is pretty simple:
foreach($array as $k => $v)
{
if(empty($v))
{
unset($array[$k]);
}
}
$show_error = count($array) == 0;
you would also have to change your encapsulation for your array values to double quotes.

Categories