search multi-dimentional array for matching elements - php

I have a multi dimensional array. I need to search through the arrays and retrieve instance of dates that match each other.
This is my array:
$dateArray = array(8) {
[0]=>
array(15) {
["bookable_id"]=>
string(1) "1"
["event_date"]=>
string(10) "2019-09-11"
}
[1]=>
array(15) {
["bookable_id"]=>
string(1) "1"
["event_date"]=>
string(10) "2019-09-11"
}
[2]=>
array(15) {
["bookable_id"]=>
string(1) "4"
["event_date"]=>
string(10) "2019-10-17"
}
[3]=>
array(15) {
["bookable_id"]=>
string(1) "4"
["event_date"]=>
string(10) "2019-10-17"
}
[4]=>
array(15) {
["bookable_id"]=>
string(1) "3"
["event_date"]=>
string(10) "2020-09-15"
}
[5]=>
array(15) {
["bookable_id"]=>
string(1) "3"
["event_date"]=>
string(10) "2020-09-15"
}
[6]=>
array(15) {
["bookable_id"]=>
string(1) "2"
["event_date"]=>
string(10) "2021-09-09"
}
}
This is my function:
function searchMatchingDates($compare, $array)
{
foreach ($array as $val) {
if ($compare["event_date"]== $val["event_date"]){
return $val;
}
}
return null;
And this is how i searched it:
foreach ($dateArray as $compare) {
$match = searchMatchingDates($compare, $array);
}
if($match){
echo "$compare['bookable_id'] + $match['bookable_id']; "
}
This works and return the date. It however return duplicate dates as the array will compare twice.
I need a way to remove an array once an array has been compared once .
For example, once array once has ran its iteration it needs to be removed so that the next array does not do a comparison on it.

If I understand the question, you want to return the dates which feature more than once in the array?
You could do this by counting all of those which feature more than once (array_count_values() https://www.php.net/manual/en/function.array-count-values.php combined with array_column()), then filtering the array based on that outcome.
// get dates which feature more than once
$dateCounts = array_filter(
array_count_values(array_column($dateArray, 'event_date')),
function ($count) {
return $count > 1;
}
);
// filter those matching dates
$matching = array_filter($dateArray, function ($date) use ($dateCounts) {
return isset($dateCounts[$date['event_date']]);
});
var_dump($matching);

Related

Array data manipulations PHP

I get from my DB data in format like this:
array(12) {
[0]=>
array(4) {
["id"]=>
string(1) "1"
["count"]=>
string(5) "78984"
["month"]=>
string(1) "6"
["hours"]=>
string(10) "10580.0833"
}
[1]=>
array(4) {
["id"]=>
string(1) "2"
["count"]=>
string(5) "64174"
["month"]=>
string(1) "6"
["hours"]=>
string(9) "6866.8333"
}
[2]=>
array(4) {
["id"]=>
string(1) "3"
["count"]=>
string(5) "31032"
["month"]=>
string(1) "6"
["hours"]=>
string(9) "3700.9167"
}
[3]=>
array(4) {
["id"]=>
string(1) "1"
["count"]=>
string(5) "91114"
["month"]=>
string(1) "7"
["hours"]=>
string(10) "11859.6000"
}
...
Each of array inside has a key: "id". It mostly look values from 1 to 3. I would like to create a new array based on this "ids" that would look like this:
array("number of unique ids") {
[0]=> "for id = 0"
array(12) {
int() count/hours
int() count/hours
int() count/hours
...
}
[1]=> "for id = 1 and so on..."
array(12){
....
}
I`ve been trying to do it like this:
$data1 = [];
$data2 = [];
$data3 = [];
foreach($data as $key => $record){
if($record['id'] == 1){
array_push($data1, $record['count']/$record['hours']);
}else if($data['id_zmiana'] == 2){
array_push($data2, $record['count']/$record['hours']);
}else{
array_push($data3, $record['count']/$record['hours']);
}
}
$raport = array_merge($data1, $data2, $data3);
And that would work, but it doesn`t look good in my opinion, beacuse what if the id change to some big number.
Yeah, having separate arrays for each ID is not a good idea. How about:
$raport = [];
foreach ($data as $record) {
$raport[$record['id']][] = $record['count'] / $record['hours']);
}
Simple, and straight to the point.
Haven't tested it. Next time try to use var_export() to export the data you put in your question. That way we can actually use it, without having to rewrite it completely.

How to get max and min value in a multidimensional array

I have this array :
array(8) {
[0]=>
array(2) {
["ticket_type"]=>
string(9) "normal"
["ticket_price"]=>
string(5) "82.00"
}
[1]=>
array(2) {
["ticket_type"]=>
string(9) "cheaper"
["ticket_price"]=>
string(5) "62.00"
}
[2]=>
array(2) {
["ticket_type"]=>
string(9) "normal"
["ticket_price"]=>
string(6) "182.00"
}
[3]=>
array(2) {
["ticket_type"]=>
string(9) "cheaper"
["ticket_price"]=>
string(6) "162.00"
}
[4]=>
array(2) {
["ticket_type"]=>
string(9) "normal"
["ticket_price"]=>
string(6) "103.00"
}
[5]=>
array(2) {
["ticket_type"]=>
string(9) "cheaper"
["ticket_price"]=>
string(5) "63.00"
}
[6]=>
array(2) {
["ticket_type"]=>
string(9) "normal"
["ticket_price"]=>
string(6) "203.00"
}
[7]=>
array(2) {
["ticket_type"]=>
string(9) "cheaper"
["ticket_price"]=>
string(6) "163.00"
}
}
I want to get the min and max price for "normal" and "cheap" ticket category, there will be more ticket categories, so can't hard code it, will get from DB, how can I do that? I'm using PHP 5.6 now, need export as array or json, Let me know if need more details.
Thank you
You can do it at the SQL level:
SELECT MIN(ticket_price) AS min_ticket_price, MAX(ticket_price) as max_ticket_price, ticket_type
FROM {your_table_name}
WHERE {your_conditions}
GROUP BY ticket_type
If you still want to do it in PHP you can just loop the array and to sort the ticket types then get the min and max values.
foreach($arr as $ticket){
$new[$ticket["ticket_type"]][] = $ticket["ticket_price"];
}
// loop the new array to only get the max and min values of each ticket type
foreach($new as $key => $n){
$res[$key]["max"] = max($n);
$res[$key]["min"] = min($n);
}
output:
array(2) {
["normal"]=>
array(2) {
["max"]=>
string(6) "203.00"
["min"]=>
string(5) "82.00"
}
["cheaper"]=>
array(2) {
["max"]=>
string(6) "163.00"
["min"]=>
string(5) "62.00"
}
}
https://3v4l.org/RcCHZ
Here is a solution to do on the php level:
$prices = [
["ticket_type"=>"normal", "ticket_price"=>"82.00"],
["ticket_type"=>"cheaper", "ticket_price"=>"62.00"],
["ticket_type"=>"normal", "ticket_price"=>"182.00"],
["ticket_type"=>"cheaper", "ticket_price"=>"162.00"],
["ticket_type"=>"normal", "ticket_price"=>"103.00"],
["ticket_type"=>"cheaper", "ticket_price"=>"63.00"],
["ticket_type"=>"normal", "ticket_price"=>"203.00"],
["ticket_type"=>"cheaper", "ticket_price"=>"163.00"],
];
// STEP:1 group by ticket types
$grouped_array = [];
foreach($prices as $price) {
$ticket_type = $price["ticket_type"];
$grouped_array[$ticket_type][] = $price["ticket_price"];
}
/*
$grouped_array = [
"normal" => ["82.00", "182.00", "103.00", "203.00"],
"cheaper => ["62.00", "162.00", "63.00", "163.00"]
];
*/
function minMax($type_array) {
$min_max = ['min'=> min($type_array), 'max'=>max($type_array)];
return $min_max;
}
// STEP 2: find min and max in each category
$min_max = [];
foreach($grouped_array as $type => $prices) {
$min_max[$type] = minMax($prices);
}
/*
$min_max = [
"normal" => ["min"=>"82.00", "max"=>"203.00"],
"cheaper => ["min"=>"62.00", "max"=>"163.00"]
];
*/
However, doing it on the database layer is best in your case. this answers "How to get max and min value in a multidimensional array".

parse php file and get dates

I am trying to parse a csv file in php to try and figure out how to get all data between some dates and the sort according to the date in ascending order but I am not able to sort the date column or I have no idea what format it is in please help
ID Reg Date FirstName LastName
1 1278336015 Sergio Roberto
2 1395656121 Ray Wilkins
3 1300276526 Trueman Ted
4 1374087492 Volt John
Please assist thanks
Okay, just for fun.
1. Parse the Data:
You could load the CSV data into an associative array like this (admittedly not very sophisticated, no error checking, validation etc):
$file = file_get_contents('CSV.csv'); // load csv into string
$rows = explode(PHP_EOL, $file); // break each line into array
$data = Array(); // where we'll store the data
foreach ($rows as $i => $row) {
$fields = explode(',', $row); // break each field into array
foreach ($fields as $col => $val) {
if ($i == 0) {
$names[] = $val; // headers in first row
} else {
$colName = $names[$col];
if ($colName == 'Reg Date') $val = date('Y-m-d H:i:s', $val);
$data[$i - 1][$colName] = $val;
}
}
}
So with your sample data above, you get:
array(4) {
[0]=>
array(4) {
["ID"]=>
string(1) "1"
["Reg Date"]=>
string(19) "2010-07-05 06:20:15"
["FirstName"]=>
string(6) "Sergio"
["LastName"]=>
string(7) "Roberto"
}
[1]=>
array(4) {
["ID"]=>
string(1) "2"
["Reg Date"]=>
string(19) "2014-03-24 03:15:21"
["FirstName"]=>
string(3) "Ray"
["LastName"]=>
string(7) "Wilkins"
}
[2]=>
array(4) {
["ID"]=>
string(1) "3"
["Reg Date"]=>
string(19) "2011-03-16 04:55:26"
["FirstName"]=>
string(7) "Trueman"
["LastName"]=>
string(3) "Ted"
}
[3]=>
array(4) {
["ID"]=>
string(1) "4"
["Reg Date"]=>
string(19) "2013-07-17 11:58:12"
["FirstName"]=>
string(4) "Volt"
["LastName"]=>
string(4) "John"
}
}
2. Sort the Data:
You can use usort() to sort by the timestamp column.
usort($data, function ($a, $b) {
if ($a['Reg Date'] == $b['Reg Date']) return 0;
return ($a['Reg Date'] < $b['Reg Date']) ? -1 : 1;
});
Results:
===After Sorting:===
array(4) {
[0]=>
array(4) {
["ID"]=>
string(1) "1"
["Reg Date"]=>
string(19) "2010-07-05 06:20:15"
["FirstName"]=>
string(6) "Sergio"
["LastName"]=>
string(7) "Roberto"
}
[1]=>
array(4) {
["ID"]=>
string(1) "3"
["Reg Date"]=>
string(19) "2011-03-16 04:55:26"
["FirstName"]=>
string(7) "Trueman"
["LastName"]=>
string(3) "Ted"
}
[2]=>
array(4) {
["ID"]=>
string(1) "4"
["Reg Date"]=>
string(19) "2013-07-17 11:58:12"
["FirstName"]=>
string(4) "Volt"
["LastName"]=>
string(4) "John"
}
[3]=>
array(4) {
["ID"]=>
string(1) "2"
["Reg Date"]=>
string(19) "2014-03-24 03:15:21"
["FirstName"]=>
string(3) "Ray"
["LastName"]=>
string(7) "Wilkins"
}
}
3. Filter the Data:
And you can use array_filter to filter the results down. I created a class to handle this (as described by #jensgram answer here)
$from = '2011-01-01';
$to = '2013-12-31';
$filtered = array_filter($data, Array(new compareDates($from, $to), 'isInRange'));
Results:
===After Filtering [2011-01-01 - 2013-12-31]:===
array(2) {
[1]=>
array(4) {
["ID"]=>
string(1) "3"
["Reg Date"]=>
string(19) "2011-03-16 04:55:26"
["FirstName"]=>
string(7) "Trueman"
["LastName"]=>
string(3) "Ted"
}
[2]=>
array(4) {
["ID"]=>
string(1) "4"
["Reg Date"]=>
string(19) "2013-07-17 11:58:12"
["FirstName"]=>
string(4) "Volt"
["LastName"]=>
string(4) "John"
}
}
Here's the simple class I used:
class compareDates
{
function __construct($from, $to)
{
$this->from = $from;
$this->to = $to;
}
function isInRange($ele)
{
if ($ele['Reg Date'] >= $this->from && $ele['Reg Date'] <= $this->to) {
return TRUE;
}
return FALSE;
}
}
NOTE: for the purpose of being able to see the date/time, I stored as
a string. But you would normally just use the numeric value to sort
by. I mention this to say that if you change the format of the date
string, it could break the sorting.

PHP: Combining data with a shared key from a single array into new array

I have this array:
array(5) {
[0]=>
array(4) {
["productCode"]=>
string(4) "X001"
["productUPC"]=>
string(3) "261"
["productTextSeq"]=>
string(1) "1"
["productTxtVal"]=>
string(5) "Text1"
}
[1]=>
array(4) {
["productCode"]=>
string(4) "X001"
["productUPC"]=>
string(3) "261"
["productTextSeq"]=>
string(1) "2"
["productTxtVal"]=>
string(5) "Text2"
}
[2]=>
array(4) {
["productCode"]=>
string(4) "X001"
["productUPC"]=>
string(3) "261"
["productTextSeq"]=>
string(1) "3"
["productTxtVal"]=>
string(5) "Text3"
}
[3]=>
array(4) {
["productCode"]=>
string(4) "X002"
["productUPC"]=>
string(3) "262"
["productTextSeq"]=>
string(1) "1"
["productTxtVal"]=>
string(5) "Text1"
}
[4]=>
array(4) {
["productCode"]=>
string(4) "X002"
["productUPC"]=>
string(3) "262"
["productTextSeq"]=>
string(1) "2"
["productTxtVal"]=>
string(5) "Text2"
}
}
With the above input, I want the output array to look like this:
array(2) {
[0]=>
array(3) {
["productCode"]=>
string(4) "X001"
["productUPC"]=>
string(3) "261"
["productTxtVal"]=>
string(17) "Text1 Text2 Text3"
}
[1]=>
array(3) {
["productCode"]=>
string(4) "X002"
["productUPC"]=>
string(3) "262"
["productTxtVal"]=>
string(11) "Text1 Text2"
}
}
The resulting array does not need the productTextSeq key, just the combined values of productTextVal, when the productCode is the same. I've searched SO for examples of this but it seems every example I've found are based on multiple input arrays. I know I can brute force this with nested foreach functions but would love a more elegant solution.
I ended up just doing it the brute force method, here is my solution if anyone's interested:
$productData = array();
$sortedData = array();
$comments = '';
$saveKey = '';
$appendComment = false;
$idx = 0;
foreach ($data as $key=>$value) {
foreach ($value as $k=>$v) {
if ($k == 'productCode') {
if ($v == $saveKey) {
$appendComment = true;
} else {
$appendComment = false;
$saveKey = $v;
if ($idx !== 0) { // Don't write to array on first iteration!
$productData['productTxtVal'] = $comments;
$sortedData[] = $productData;
}
}
}
if ($k == 'productTxtVal') {
if ($appendComment == true) {
$comments .= ' ' . trim($v);
} else {
$comments = trim($v);
}
}
}
$productData = $value;
$idx++;
}
Not "elegant" but it works. I also have a check after this logic in case only one productCode is in the original array, as it won't be written to the $sortedData array since the key never changes.
The following code assumes you control the contents of the original data array (due to risk of injection using extract() function) and that no 2 items with the same productCode have the same productTextSeq.
$products = [];
foreach ($data as $item) {
// extract contents of item array into variables
extract($item);
if (!isset($products[$productCode])) {
// create product array with code, upc, text as array
$products[$productCode] = compact('productCode', 'productUPC') + ['productTxtVal' => []];
}
// add text value to array with sequence as index
$products[$productCode]['productTxtVal'][$productTextSeq] = $productTxtVal;
}
$products = array_values( // ignore array keys
array_map(function($product) {
ksort($product['productTxtVal']); // sort text as array by index/ sequence
$product['productTxtVal'] = implode(' ', $product['productTxtVal']); // implode into string
return $product;
}, $products)
);
You can run the code here: https://repl.it/BWQL

How to update a multi-array value?

I have this multidimension array in which I need to update a value. What would be the best way to do so? I tried it with 2 foreach loops but wasn't sure if that was the right approach.
Here is the array in question. I need to update the dollar amount on each sub array (i.e. add 3 to it).
array(6) { ["Ground"]=> array(2) { [0]=> string(3) "USD" [1]=> string(5) "13.63" }
["3 Day Select"]=> array(2) { [0]=> string(3) "USD" [1]=> string(5) "25.26" }
["2nd Day Air"]=> array(2) { [0]=> string(3) "USD" [1]=> string(5) "32.43" }
["Next Day Air Saver"]=> array(2) { [0]=> string(3) "USD" [1]=> string(5) "63.00" }
["Next Day Air"]=> array(2) { [0]=> string(3) "USD" [1]=> string(5) "68.65" }
["Next Day Air Early AM"]=> array(2) { [0]=> string(3) "USD" [1]=> string(6) "103.68" } }
Your foreach loop approach would be correct, unless you expect the data format to change e.g. to have more nested levels. If that were the case, then a recursive function would be best suited.
Also, if the data is expected to remain uniform, you could do this:
foreach( $my_array as $index => $row ){
$my_array[$index][1] += 3;
}
cheers!
foreach ($arr as $k=>$row) {
$arr[$k][1] = floatval($row[1]) + 3;
}
foreach ($array as &$subarray) {
foreach ($subarray as $key=>&$value) {
// do whatever you want with $value
// ...
$value = 'something else'; // example
}
}
Try this:
<?php
foreach($first_array as $first_dem_key)
$first_array[$first_dem_key][1] = $first_array[$first_dem_key][1] + 3;
?>

Categories