PHP multidimensional array counter - php

Im trying to make a multidimensional array with two columns. Name and Counter. I can do a single array with all the names. But I dont know how to make it multidimensional and be able to still update the counters. Code i got so far is
if (!in_array($prodname, $da)){
array_push($da, $prodname);
}
and then I can dump it back out with a foreach. How do I make it two dimensional? How can I say alright this exists update the old value? etc.

If you only need name and counter then you should just be able to use a normal array:
$nameCountArray = array();
foreach($names as $name){
if(!array_key_exists($name,$nameCountArray)){
$nameCountArray[$name] = 1;
}else{
$nameCountArray[$name] = $nameCountArray[$name] + 1;
}
}
If you do need multidimensional arrays these are just arrays of arrays and can be accessed as such. A good example of this is using a 2d array to store locations (say on a 3 by 3 grid):
$twoDArray = array(
0 => array(0 => 1,
1 => 4,
2 => 7),
1 => array(0 => 2,
1 => 5,
2 => 8),
2 => array(0 => 3,
1 => 6,
2 => 9)
);
//Grab the item at 1,2
$item = $twoDArray[1][2];//Will give '8'

Supposing you want $da to look like this:
Array(
"name1" => array("score1" => 80, "score2" => 100),
"name2" => array("score1" => 50, "score2" => 60),
"name3" => array("score1" => 90, "score2" => 80),
...
)
Then all you need to do is something like:
function setScore($prodName, $scoreName, $score)
{
global $da;
if (!array_key_exists($prodName, $da)) {
$da[$prodName] = array();
}
$da[$prodName][$scoreName] = $score;
}
setScore("name1", "score1", 80);
setScore("name1", "score2", 100);
setScore("name2", "score1", 50);
...
Unless I'm misunderstanding your question, which is very possible.

Related

How do I get the position of an element in an array in php/laravel

So I have a
student model,
subject model,
marks model, which has the total score field
what I am trying to do is get the total score in an exam for each student in a class and then retrieve the results according to the highest score in the class and then position those scores as 1,2,3...
then finally get the position a single student and store it in an exam record table.
so far I was able to achieve getting the total score in an exam for each student, stored them in an array, sorted them according to the highest score,
the only issue now giving me a headache is getting the position of those scores from the array, my question is how can I get the position of a score for a student, or is there a way to add the positions to the scores and then retrieve the position for a student
For example
1 student_id => 2, total_score => 500
2 student_id => 3, total_score => 455
3 student_id => 5, total_score => 345
here is my code below, Please anyone with an idea how to solve this I need your help.
TextInput::make('position')->numeric(
function (Closure $set) {
// Get all students from class
$studentsInClass = $this->class->students;
//empty array to store student's total_score
$totalScore = [];
// loop through students get all their total_score on all subjects from mark table and sum it, then store it
in totalScore array.
foreach ($studentsInClass as $key => $student) {
$totalScore[] = array('student_id' => $student->id, 'total_score' => $student->marks->sum('total_score') );
}
// Sort scores from highest to lowest
$sortedScores= array_values(array_reverse(Arr::sort($totalScore, function ($value) {
return $value['total_score'];
})));
// get the current student Id
$id = $this->student->id;
// find a student in the array that matches the current student id and return his score.
//so this is where I would like to return the score and position of the student
$filteredArray = Arr::where($sortedScores, function ($value, $key) use ($id) {
return $value['student_id'] == $id;
});
}
)->disabled(),
if you dd($sortedScores)
You have a two-dimensional array.
$sortedScores = [
['student_id' => 2, 'total_score' => 443],
['student_id' => 4, 'total_score' => 410],
['student_id' => 1, 'total_score' => 371],
['student_id' => 3, 'total_score' => 170],
];
The index of each row is already consecutive from 0-3. I think you want to add a rank to the rows.
foreach($sortedScores as $idx => $row)
$sortedScores[$idx]['rank'] = $idx+1;
//test output
var_export($sortedScores);
Output:
array (
0 =>
array (
'student_id' => 2,
'total_score' => 443,
'rank' => 1,
),
1 =>
array (
'student_id' => 4,
'total_score' => 410,
'rank' => 2,
),
2 =>
array (
'student_id' => 1,
'total_score' => 371,
'rank' => 3,
),
3 =>
array (
'student_id' => 3,
'total_score' => 170,
'rank' => 4,
),
)
If you want rank to start at 0, just assign $idx.
Try on https://3v4l.org/9Dv7D
I hope this helps and that I understood your problem correctly.
To find the key for a specific value in a multidimensional array see 'PHP Multidimensional Array Searching (Find key by specific value)'
You can use the array_search() function. This will either return the key of the value you are looking for or false if it is not in the array.
$letters = ['a', 'b', 'c', 'd'];
$key = array_search('b', $letters);
//In this case $key will equal to 2.
Presuming that $filteredArray contains a single item, then the first key should be the student's position in the sorted array.
$position = array_keys($filteredArray)[0];

Trying to merge two results of SQL queries - ToDoList App

I am trying to merge two results of two queries in MYSQL using PHP, but I am puzzled how to do it! I am using PDO. I am programming for a hobby and am trying to make a to do list app just like a Trello board. However, I just can't figure out how to merge two results from different tables in a database.
The idea is as follows:
I have a table called 'task_lists' with the content:
'list_id => 1, list_name = 'listOne'
'list_id => 2, list_name = 'listTwo'
And a table called 'tasks':
task_id => 1, list_id => 1, task_name => 'taskOfListOne', duration => 5, is_done => 1
task_id => 2, list_id => 1, task_name => 'anotherTaskOfListOne', duration => 5, is_done => 1
task_id => 3, list_id => 2, task_name => 'taskOfListTwo', duration => 10, is_done => 0
And I am trying to create an array that is merged between the two results as something like:
(I know this is a rough picture of how the array is supposed to look like)
$result = [array]
[list_id] = 1, [list_name] = 'listOne' =>
[array][list_id] = 1, ['task_name] = taskOfListOne,[duration] = 5, ['is_done'] => 1
[array][list_id] = 1, ['task_name] = anotherTaskOfListOne,[duration] = 5, ['is_done'] => 1
[list_id] = 2, [list_name] = 'listTwo' =>
[array][list_id] = 2, ['task_name] = taskOfListTwo,[duration] = 5, ['is_done'] => 1
Is this even possible? I have tried a Union sql query and methods like nested foreach statements, but none of them worked for me. Am I missing something here?
PS: Sorry for my bad english.
Have you tried a left join?
SELECT TL.`list_id`, TL.`list_name`, T.`task_name`, T.`duration`
FROM task_lists AS TL
LEFT JOIN tasks as T ON TL.`list_id` = T.`list_id`
And then in PHP you build the array in the format you want.
Later edit:
Simple PHP example to parse SQL data as you asked (to remove duplicated info):
<?php
// $mysql_rows -> here is your query result, fetched as associative array
$filtered_array = array();
foreach ($mysql_rows as $row){
// Initiate record if is not already initiated
if (!isset($filtered_array[ $row['list_id'] ])){
$filtered_array[ $row['list_id'] ] = array(
'list_id' => $row['list_id'],
'list_name' => $row['list_name'],
'tasks' => array()
);
}
// Add tasks
$filtered_array[ $row['list_id'] ]['tasks'][] = array(
'task_name' => $row['task_name'],
'duration' => $row['duration'],
'is_done ' => $row['is_done ']
);
}
// Optional: if you want to remove list_id from $filtered_array key names, uncomment the next line
// $filtered_array = array_values($filtered_array);
?>

Adding an array of values to an existing array

I've got a foreach where I create an array out of id's, based on the submitted selected checkboxes from my form (which are `checkbox[$id]. So I end up with:
Where 1, 2 and 3 are the submitted id's from the form. So far so good.
Now I also have an input field amount[$id]in my form. When selecting a checkbox, I can enter an amount for that row and submit the results. I need to add the values of amount to my array if id's. My end result should look like this:
[1 => ['amount' => '10'], 2 => ['amount' => '12'], 3 => ['amount' => '5'] // And so on
I tried merging, and array_push, but I seem to be doing it wrong, since I cannot figure it out. Any pointers?
Something like this should work:
$result = [];
$ids = [1,2,3]; // I suppose it is `$_POST['ids']`
$amounts = [1 => 10, 2 => 11, 3 => 22]; // I suppose it is `$_POST['amount']`
foreach ($ids as $id) {
if (!empty($amounts[$id])) {
$result[$id] = ['amount' => $amounts[$id]];
}
}
Using array_combine as advised in comments can be used only if sizes of arrays are equal. So if you have something like:
$ids = [1,2,4];
$amounts = [1 => 10, 2 => 11, 3 => 0, 4 => 22];
print_r(array_combine($ids, $amounts)); // PHP Warning
And second fact - array_combine won't create values as arrays. So
$ids = [1,2,3];
$amounts = [1 => 10, 2 => 11, 3 => 10];
print_r(array_combine($ids, $amounts)); // no subarrays here

php logic loop step by 5

I am reading an excell file with php. No problem with that but I am stuck on a little logical part. I want to make an array that containts multiple other arrays with data.
The data is provided in my excell file I know from what column should start reading but not when to stop because this is dynamic.
My question is how can a make a loop that reads my columns and makes on every 5th column a new array.
so what I want is something like this:
(My data for the excell file is proved in $line[] each column has its number.)
array(
'length' => $line[15],
'width' => $line[16]
'price_per' => $line[17],
'price' => $line[18],
'stock' => $line[19]
),
array(
'length' => $line[20],
'width' => $line[21]
'price_per' => $line[22],
'price' => $line[23],
'stock' => $line[24]
),
array(
'length' => $line[25],
'width' => $line[26]
'price_per' => $line[27],
'price' => $line[28],
'stock' => $line[29]
), ....
So how can I make this dynamic (for loop ?) so that I have 1 big indexed Array , with multiple asscociated arrays? Note: my for loop should always star from line[15]!
To begin with, if $line has any elements that you don't want to process (e.g. the first 15 as your example indicates), slice them off with array_slice:
$line = array_slice($line, 15);
Then use array_chunk to split your original array into as many pieces as there are:
$chunks = array_chunk($line, 5);
Then, turn each chunk into its own array by associating each value with the correct key using array_combine:
$results = array();
$keys = array('length', 'width', 'price_per', 'price', 'stock');
foreach ($chunks as $chunk) {
$results[] = array_combine($keys, $chunk);
}
for($i = 15; $i < ????; $i += 5)
{
$your_array[] = array(
'length' => $line[$i],
'width' => $line[$i+1]
'price_per' => $line[$i+2],
'price' => $line[$i+3],
'stock' => $line[$i+4]
);
}
Replace ???? by the number of lines

Merge multidimensional array data by one column and ensure all rows contain all columns

I have an array which contains data from two or more database queries.
The merging needs to be done by a specified column (date in this case) and the resultant rows must contain all associative keys from the original array.
$array = [
[
['date' => '2011-01-17', 'col-1' => 58, 'col-2' => 54],
['date' => '2011-01-19', 'col-1' => 50, 'col-2' => 61],
['date' => '2011-01-20', 'col-1' => 44, 'col-2' => 22],
['date' => null, 'col-1' => 448, 'col-2' => 196],
],
[
['date' => '2011-01-17', 'col-3' => 1489],
['date' => '2011-01-18', 'col-3' => 1534],
['date' => null, 'col-3' => 1534],
]
];
I'd like to merge data that is related by the date value, make sure that every row contains all possible columns, and is sorted by date with the empty-dated row occurring last.
Desired output:
array (
0 =>
array (
'date' => '2011-01-17',
'col-1' => 58,
'col-2' => 54,
'col-3' => 1489,
),
1 =>
array (
'date' => '2011-01-18',
'col-1' => NULL,
'col-2' => NULL,
'col-3' => 1534,
),
2 =>
array (
'date' => '2011-01-19',
'col-1' => 50,
'col-2' => 61,
'col-3' => NULL,
),
3 =>
array (
'date' => '2011-01-20',
'col-1' => 44,
'col-2' => 22,
'col-3' => NULL,
),
4 =>
array (
'date' => NULL,
'col-1' => 448,
'col-2' => 196,
'col-3' => 1534,
),
)
Additional notes:
The input array may have a count greater than 2.
Subarray may have differring counts and are not relatable by their index.
First, I'm going to assume your data is sorted by date, since you can do it in SQL and it's sorted in your example. You need to walk through all of your sets at the same time, merging as you go.
$merged = array();
$i_first = 0;
$i_second = 0;
$count_first = count($data[0]);
$cound_second = count($data[1]);
while ($i_first < $count_first || $i_second < $count_second)
{
// this comparison depends on what your merge_by is
$diff = strtotime($data[$i_first]['date']) - strtotime($data[$i_second]['date']);
if ($diff == 0)
{
$merged[] = array_merge($data[$i_first], $data[$i_second]);
$i_first++;
$i_second++;
}
elseif ($diff < 0) // first date is earlier
{
$i_first++;
}
else // second date earlier
{
$i_second++;
}
}
Now your $merged array should have what you want. Note that this solution assumes you don't have duplicate date rows in one chunk, or it would overwrite the existing results. Also, you could expand to have more than two data sets if you want.
Populate an array of default values to ensure that rows will contain null values for all expected columns by using two rounds of a flattening technique then mapping all keys to null values for later use.
Use nested loops to access and push rows of data into the result array. Use temporary first level keys to identify unique date groups. To aid in the sorting of rows later, use the Elvis operator (?:) to fallback to the literal string 'last' when defining the first level key -- all other date values will be alphabetically sorted before this key.
While iterating, if the current row contains a date which has not been encountered before, overwrite the default values with its values and push that data into that group's row. If the current row contains a date which has been encountered before, overwrite the cached group data with the new data.
After looping, sort the array by its first level keys.
To remove the temporary first level keys, call array_values().
Code: (Demo)
$defaults = array_map(
fn() => null,
array_merge(...array_merge(...$array))
);
$result = [];
foreach ($array as $set) {
foreach ($set as $row) {
$key = $row['date'] ?: 'last';
$result[$key] = array_replace($result[$key] ?? $defaults, $row);
}
}
ksort($result);
var_export(array_values($result));

Categories