array length count doesn't match - php

When i set a global array as this
$items[$users[$clientID]['room']] = array("seat" => $seat, "item_id" => $q[1], "room" => $users[$clientID]['room']);
it is
$items[4] = array("seat" => 20, "item_id" => 10, "room" => 4);
but when i do a count it telling the length of $items[4] is 3? It should only count 1 because i only have "1" item.
for ( $i=0;$i<count($items[$users[$clientID]['room']]);$i++):
//something
endfor;
print_r($items[$users[$clientID]['room']]);
outputs:
Array
(
[seat] => 43
[item_id] => 46
[room] => 5
)
COUNT 3
What am i doing wrong?

You have defined $items[$users[$clientID]['room']] as one array: but an array that comprises three items - seat, item_id and room - and it is those individual array items that you are counting.

$items[$users[$clientID]['room']] is an array and count() returns no of element in an array, if the value to count is not an array it will return 1. See this link for more information about count function.
Count Function - PHP

Related

Find min value in multidimensional array and return key

I have read several similar questions on here, such as this, Finding the minimum value's key in an associative array but I think my problem may be unique in that my source array is not strings as keys.
My source array looks like this,
$dealers = array(
array(
[id] => 1526,
[count] => 2
),
array(
[id] => 1518,
[count] => 5
),
array(
[id] => 1511,
[count] => 9
),
array(
[id] => 1410,
[count] => 3
)
);
I need to get the id of the smallest count value.
I have tried the following,
$low_dealer = array_keys($dealers, min($dealers));
But it appears to be returning the index of the lowest id and not count.
My next attempt was combining another function I found to find the min of the specific column,
$low_dealer = array_keys($dealers, min( array_column( $dealers, 'count' ) ));
But that returned nothing.
EDIT: Also must be able to handle multiple mins, if two or more have the same count number, need to get an array of them back so I can rand() it.
Would appreciate any tips here, thank you!
// indexed array: 2, 5, 9, 3
$counts = array_column($dealers, 'count');
// find index of min value
$index = array_search(min($counts), $counts, true);
// $dealers[$index]['id'];
$dealersMin = min(array_column($dealers, 'count'));
$dealersWithMinCount = array_filter($dealers, function ($dealer) {
global $dealersMin;
return ($dealer['count'] == $dealersMin);
});
var_dump($dealersWithMinCount[array_rand($dealersWithMinCount)]['id']);
eval.in demo
Explanation
First we find the lowest value of 'count' in the array and save that to $dealersMin.
Then we need to get all rows in the $dealers array that have a count of $dealersMin and save that in $dealersWithMinCount.
Then just pick a random element of $dealersWithMinCount with array_rand()

Sum of array values based on similar values from another array

This might be a little confusing, but I am going to explain it as best as I can. Please bear with me.
I have the following arrays:
Array
(
[question1] => 69
[question2] => 36
[question3] => 57
[question4] => 69
[question5] => 58
[question6] => 40
[question7] => 58
)
Array
(
[question1] => 8
[question2] => 6
[question3] => 5
[question4] => 6
[question5] => 7
[question6] => 8
[question7] => 5
)
As you can see the two arrays have identical keys, but different values for each key.
I need to find the keys in the second array that have the same values, so [question1] and [question6] both have a value of 8. And then in the first array I need to add together the values of [question1] and [question6] because they have a like value in the second array. I need to add the first array values together based on matching values in the second array (if that makes any sense)
Ideally, the output would be another array that would look something like this:
Array
(
[5] => 115
[8] => 109
[6] => 105
[7] => 58
)
Where the value of the second array becomes the key and the sum of the added values from the first array is the value.
Now I won't be picky here, so if we can't get it into that exact format then that is okay. I just need to be able to add together the values in the first array based on the similar values in the second array.
I hope this makes sense. If it doesn't please comment and I will do my best to explain further.
The simplest solution is to iterate over the second array. Lookup the key into the first array and if it exists then add the corresponding value from the first array into the result array, indexed by the value from the second array.
Something like this:
$array1 = array(
'question1' => 69,
'question2' => 36,
'question3' => 57,
'question4' => 69,
'question5' => 58,
'question6' => 40,
'question7' => 58,
);
$array2 = array(
'question1' => 8,
'question2' => 6,
'question3' => 5,
'question4' => 6,
'question5' => 7,
'question6' => 8,
'question7' => 5,
);
// Compose the desired result here
$result = array();
// Iterate over the second array; its values become keys in the result array
foreach ($array2 as $key => $val) {
// If this is the first time when this value is reached then a corresponding
// value does not yet exists in the result array; add it
if (! isset($result[$val])) {
$result[$val] = 0;
}
// Lookup the key into the first array
if (isset($array1[$key])) {
// If it exists then add its value to the results
$result[$val] += $array1[$key];
}
}
// That's all
print_r($result);

String to Multidimensional Array with merging and sorting

I have this sort of string that come from my database after many use of CONCAT().
1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10
In order to have something clear, let's say this :
The large string is made of multiple substring, all ending by a ;
Each substring is made of four elements :
A first number. Let's call it the Group
A letter or group of letters. They are called the Section
A second number. We will call it From
A third and last number. We will call it To
Using this code
$data = "1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10";
echo $data;
$ret = array_map (
function ($_) {return explode (', ', $_);},
explode (';', $data)
);
I get the following multidimensional array
Array
(
[0] => Array
(
[0] => 1
[1] => AA
[2] => 6
[3] => 10
)
[1] => Array
(
[0] => 1
[1] => Z
[2] => 1
[3] => 5
)
[2] => Array
(
[0] => 2
[1] => AE
[2] => 1
[3] => 5
)
[3] => Array
(
[0] => 2
[1] => AF
[2] => 6
[3] => 10
)
[4] => Array
(
[0] => 3
[1] => X
[2] => 1
[3] => 5
)
[5] => Array
(
[0] => 3
[1] => Y
[2] => 5
[3] => 10
)
)
I want to end with a multidimensional array that looks like that :
Array
(
[0] => Array
(
[0] => 1
[1] => Array
(
[0] => Z
[1] => 1
[2] => 5
)
[2] => Array
(
[0] => AA
[1] => 6
[2] => 10
)
)
[1] => Array
(
[0] => 2
[1] => Array
(
[1] => AE
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => AF
[2] => 6
[3] => 10
)
)
[2] => Array
(
[0] => 3
[1] => Array
(
[1] => X
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => Y
[2] => 6
[3] => 10
)
)
)
I don't know what's the best method to do it in order to get this result nor if it's possible without too complex operations.
What's the best approach to get the final result ? Should I work on the "raw" multidimensional array or should I work from the string from the beginning ?
Merging arrays with same Group
First, I want to merge substring starting with the same Group value. The rest of each string then become another array inside the newly created array.
I think I can do this by parsing the initial array (Or maybe the string itself ?) and pushing the results in a new one, merging the data in the same time.
In my example, it has been done to the six starting arrays that are now grouped into three arrays.
Sorting using the From and To values
After my substrings with the same Group value are combined into arrays, I want to sort these arrays so the To value of a sub-array is always smaller to the From value of the next one.
The initial string are always generated with the following rules :
There will never be overlapping From and To values like that : 1,5 - 4,7. It would be either 1,4 - 5,7 or 1,5 - 6,7
There will never be missing number in a sequence so you will never have something like 1,3 - 5,7
The From and To value of the same array can be the same. So you can get : 1,4 - 5,5 - 6,7
That's why 1, AA, 6, 10; 1, Z, 1, 5; has been sorted to Z, 1, 5 followed AA, 6, 10. Is there a PHP function that can do this kind of sorting (By comparing values with a different key) or should I create my own ?
Also, if you think that I should totally change the way I want to do this (Using multidimensional arrays...) and you have some ideas, go ahead and share them. I'm also here to learn new way to do things.
Edition concerning Database structure
As stated by #deceze, it may be easier to construct my initial string differently during my SQL query. I have tried it but I'm probably not skilled enough to get what I want. My database looks like that :
Database Structure
As you can see, all the rows are linked by a MasterID. This is because I'm doing a 1 to n query on multiple table.
So far, my query looks like that (I removed all the unnecessary stuff from it) :
SELECT s.MasterID,
GROUP_CONCAT(CONCAT( CONCAT( CONCAT( CONCAT( CONCAT(
s2d.Group, ', '),
s2d.Section, ', '),
s2d.From),', '),
s2d.To) SEPARATOR '; ') AS Concatstuff,
FROM table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
WHERE MasterID = $MasterID (A PHP variable)
Because of the 1 to N relation, I don't know how to make this differently. Maybe I could keep it simpler and perform two queries instead of one. In the first query, I get the information from table1 and in the second query, the informations from table2.
But if you know a way to do all of that in only one query, I'm eager to learn how you can do this !
I'd recommend modifying your MySQL query before making many PHP changes.
That massive list of concats will grow quite large, eventually you may even need to adjust the MySQL config setting for GROUP_CONCAT() since it'll truncate after a certain length.
Instead, we can keep the GROUP_CONCAT() and group specifically on individual masterid / group combinations with a GROUP BY. Additionally, GROUP_CONCAT() has an ORDER BY attribute which should solve the sorting issue:
SELECT
s.MasterID,
s2d.`group`,
GROUP_CONCAT(
s2d.`section`, ',', s2d.`from`, ',', s2d.`to`
ORDER BY `from`, `to`
SEPARATOR ';'
) AS Concatstuff
FROM
table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
GROUP BY
s.MasterID, s2d.`group`
WHERE
s.MasterID = $MasterID;
This should give us data similar to:
MasterID group Concatstuff
2 1 z,1,5;aa,6,10
2 2 ae,1,5;af,6,10
2 3 x,1,5;y,6,10
Assuming you've retrieved this from the database and have it stored in an array named $results, we can iterate over it like:
$final_groups = array();
foreach ($results as $group) {
// your original `array_map()` logic:
$split_group = array_map(function($_) {
return explode(',', $_);
},
explode(';', $group['Concatstuff'])
);
// ... any other processing you want to do
// store the results:
$final_groups[$group['group']] = $split_group;
}
Note: to explicitly answer your question
Is there a PHP function that can do this kind of sorting
Yes, usort():
function sort_group($a, $b) {
// [1] = 'from'
// [2] = 'to'
if ($a[1] == $b[1]) {
if ($a[2] == $b[2]) {
return 0;
}
return ($a[2] < $b[2]) ? -1 : 1;
}
return ($a[1] < $b[1]) ? -1 : 1;
}
usort($split_group, 'sort_group');
You can customize the comparison logic within sort_group() to match whatever you want it to be. Above, I have it sorting on both from and to =]
Trying to give a general answer without writing your code for you:
For each group, you would set use the group number as index for the contained data.
For each group, you will write its group index into the element with index string prefix plus the number zero: $ret1[$group_number]['d0'] = $group_number;. It will get overwritten every time you add stuff to the group.
Then add the group content with some string index appropriate for sorting. I would propose producing an index using sprintf(), like $idx = sprintf('d%05.1f%05.1f', $from, $to);, so the group number will always be sorted ahead. Again here the prefix. Add it with $ret1[$group_number][$idx] = $group_array;.
Once you have completed this for all input data, run over it for sorting and finishing:
Iterate over all groups in $ret1, sort them by keys and remove the keys with array_values(). Add them to a new array with $ret[] = ....

How can I get all array elements, where the value only occurs once in the array?

I'm trying to get all array elements, where the value only occurs once in the array.
I tried to use:
array_unique($array);
But this does only remove the duplicates, which is not what I want.
As an example:
$array = 0 => 1
1 => 2
2 => 3
3 => 4
4 => 5
5 => 2
6 => 3
7 => 4
8 => 5
Expected output:
array(
0=>1
)
As you can see only the value 1 occurs once in the array, all other values are more than once in the array. So I only want to keep that one element.
This should work for you:
First use array_count_values() to count how many times each value is in your array. This will return something like this:
Array (
[1] => 1
[2] => 2
[3] => 2
[4] => 2
[5] => 2
// ↑ ↑
// Value Amount
)
After that you can use array_filter() to only get the values, which occurs once in your array. Means:
Array (
[1] => 1
[2] => 2
[3] => 2
[4] => 2
[5] => 2
)
And at the end simply use array_keys() to get the value from the original array.
Code:
<?php
$arr = [1,2,3,4,5,2,3,4,5];
$result = array_keys(array_filter(array_count_values($arr), function($v){
return $v == 1;
}));
print_r($result);
?>
output:
Array (
[0] => 1
)
You can use array_count_values to get the number of times each value exists in the array. You can use this to get all the values that occur only once by looking at the value in the returned array.
If you already have an array and it is in the structure described above, you should be able to just array_search(1, $array) and it will give you the key of the array with the value of 1. Or if you expect to have multiple keys with the value of 1, you can use array_keys($array, 1) and it will return an array of keys that have the value of 1. Hope this helps.

If value exists in one PHP array, add value to second array

I have two PHP arrays. One contains a group name and another contains a pay wage value.
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 1 [3] => 3 );
This means there are four employees on the schedule. Two are assigned to group 1, another to group 4 and the last to group 3.
The second array is as follows:
$tot_wages_array = Array ( [0] => 500 [1] => 44 [2] => 80 [3] => 11.25 );
This is a sample array of each employee's wage. Both arrays are constructed in order as values are added in a mysql while loop as it pulls the info from the database.
Later on down the line, I combine the two arrays to get one array where the key is the group number and the value is the total wages for that group:
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
This works like a charm EXCEPT for when more than one employee is assigned to the same group. These arrays are built in a mysql while loop as it loops through each employee's info:
array_push($tot_wages_array, $totemp_wages_sch); // Add their wage to the array
array_push($group_wages_array, $emp_data['group_id']); // Add their group to the array
Instead of just pushing the data to the array, I need to do this... I know the english but I don't know how to code it:
If $emp_data['group_id'] exists as value in $group_wages_array, add nothing to this array but get the key. Add $totemp_wages_sch to $tot_wages_array where key = group_wages_array key
I know it sounds more like an SQL query but I have to keep the keys and values in order so that they can be combined later in the page. If I can get this to work right, The arrays shown in the example would be:
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 3 );
$tot_wages_array = Array ( [0] => 580 [1] => 44 [2] => 11.25 );
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
$combined_group_wages = Array ( [1] => 580 [4] => 44 [3] => 11.25 );
...I've got to make this work using PHP. Any ideas?
I came up with a solution based on a combination of two of the answers submitted below. Here it is if it can help someone:
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] += $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
array_push($tot_wages_array, $totemp_wages_sch);
}
This should do it:
$group_wages_array = array(1, 4, 1, 3);
$tot_wages_array = array(500, 44, 80, 11.25);
$combined_group_wages = array();
for ($i=0; $i<count($group_wages_array); $i++) {
$group = $group_wages_array[$i];
if (array_key_exists($group_wages_array[$group], $combined_group_wages)) {
$combined_group_wages[$group] += $tot_wages_array[$i];
} else {
$combined_group_wages[$group] = $tot_wages_array[$i];
}
}
print_r($combined_group_wages);
Yields:
Array
(
[1] => 580
[4] => 44
[3] => 11.25
)
But I recommend that you just switch to using objects to better represent your data.
If I could see the entirety of the code that would help a lot, but here's your English converted to php. Show me more code and I can perfect it, until then try this ->
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] = $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
}

Categories