I'm trying to check if an array element exists already, and if it doesn't, I need to create an array element with just one value populated and the second value set to null. The added complexity is that I need to ignore the second level while checking the array without having to loop through the array again, as it can be quite a big array.
My array looks like this:
Array
(
[2016-05-28] => Array
(
[0] => Array
(
[store] => 1
[price] => 12
)
[1] => Array
(
[store] => 7
[price] => 18
)
[2] => Array
(
[store] => 9
[price] =>
)
)
)
I'm trying to check if there is an existing element that has a store value x and if it doesn't exist I create a new element, if it does exist I ignore it and move on.
For this example I have hard coded the $day
and $store
variables but this would usually be populated in a for loop and then in turn the below snippet would be run inside the for loop.
My code:
$day = '2016-05-28';
$store = 8;
if (!$history[$day][][$store]) {
$history[$day][] = array(
"store" => $store
, "price" => null
);
}
The problem is on checking if the element exists if (!$history[$day][][$store]) {
, is it possible to ignore the second level between the $day
element and $store
element so that it will check for the store
element to see if it exists, can I use a wild card or will in_array
work?
Here's the full piece of code I'm currently using.
$setPriceHistoryData = $daoObj->getSetPriceHistoryData($set['id']);
$chartDays = date('Y-m-d', strtotime('-30 days'));
$priceHistoryData = array();
$endDay = date('Y-m-d');
while ($chartDays <= $endDay) {
for ($i = 0; $i < count($setPriceData["price_history_store_data"]); $i++) {
for ($j = 0; $j < count($setPriceHistoryData); $j++) {
if ($setPriceData["price_history_store_data"][$i]["id"] == $setPriceHistoryData[$j]["vph_store"]
&& $chartDays == $setPriceHistoryData[$j]["vph_date"]) {
$priceHistoryData[$chartDays][] = array(
"store" => $setPriceHistoryData[$j]["vph_store"]
, "price" => $setPriceHistoryData[$j]["vph_price"]
);
} else {
if (!$priceHistoryData[$chartDays][]["store"]) {
$priceHistoryData[$chartDays][] = array(
"store" => $setPriceHistoryData[$j]["vph_store"]
, "price" => null
);
}
}
}
}
// Increment day
$chartDays = date('Y-m-d', strtotime("+1 day", strtotime($chartDays)));
}
I would loop through all the dates. For each day, loop through all the store numbers you expect to find. Use array_filter
to find the required stores. If you don't find a required store, add it.
$required_stores = [1,2,3,4]; // stores you wish to add if missing
$source = [
'2016-06-15'=>[
['store'=>1,'price'=>10],['store'=>2,'price'=>10],
],
'2016-06-16'=>[
['store'=>1,'price'=>10],['store'=>3,'price'=>10],
],
'2016-06-17'=>[
['store'=>3,'price'=>10],['store'=>4,'price'=>10],
],
];
//go through all dates. Notice we pass $stores as reference
//using "&" This allows us to modify it in the forEach
foreach ($source as $date => &$stores):
foreach($required_stores as $lookfor):
//$lookfor is the store number we want to add if it's missing
//will hold the store we look for, or be empty if it's not there
$found_store = array_filter(
$stores,
function($v) use ($lookfor){return $v['store']===$lookfor;}
);
//add the store to $stores if it was not found by array_filter
if(empty($found_store)) $stores[] = ['store'=>$lookfor,'price'=>null];
endforeach;
endforeach;
// here, $source is padded with all required stores
As Rizier123 suggested, you could go with array_column(). Yous could write a simple function that would accept a store num, a history array by reference and the day:
$history = [
'2016-05-28' => [
['store' => 1, 'price' => 23],
['store' => 2, 'price' => 23],
['store' => 3, 'price' => 23]
]
];
$store = 8;
$day = '2016-05-28';
function storeHistory($store, &$history, $day)
{
if ( ! isset($history[$day])) {
return false;
}
$presentStores = array_column($history[$day], 'store');
if ( ! in_array($store, $presentStores)) {
$history[$day][] = ['store' => $store, 'price' => null];
}
}
storeHistory($store, $history, $day);
var_dump($history);
array (size=1)
'2016-05-28' =>
array (size=4)
0 =>
array (size=2)
'store' => int 1
'price' => int 23
1 =>
array (size=2)
'store' => int 2
'price' => int 23
2 =>
array (size=2)
'store' => int 3
'price' => int 23
3 =>
array (size=2)
'store' => int 8
'price' => null
<?php
$history = array(); // Assuming that's array's identifier.
$history['2016-05-28'] = array (
array('store' => 1, 'price' => 12),
array('store' => 7, 'price' => 18),
array('store' => 9, 'price' => 20)
);
// variables for the if condition
$day = '2016-05-28';
$store = 8;
$match_found = FALSE;
foreach($history[$day] as $element) {
if ($element['store'] == $store) {
$match_found = TRUE;
}
else {
continue;
}
}
if ($match_found == TRUE) {
// I included a break statement here. break works only in iterations, not conditionals.
} else {
array_push($history[$day], array('store' => $store, 'price' => null));
// I was pushing to $history[$date] instead of $history[$day] since the variable I created was $day, NOT $date
}
I rewrote the PHP snippet simply because the key-value declaration was giving some errors. For example the 2016-05-28
key element supposed to be either a string or an integer, according to PHP specifications ( http://php.net/manual/en/language.types.array.php ).
So your code snippet would have appeared like the code above.
I edited the code to append the data into the main date element instead of the root
A couple nested loops should do it, and I thought you might want to create a new date element if it doesn't exist in history either.
code is commented:
<?php
$history = Array
(
'2016-05-28' => Array
(
0 => Array
(
'store' => 1,
'price' => 12
),
1 => Array
(
'store' => 7,
'price' => 18
),
2 => Array
(
'store' => 9,
'price' => null
)
)
);
print_r($history);
$day = '2016-05-28';
$store = 8;
// loop through dates
foreach ($history as $key=>&$date){
// scan for date
$found_date = false;
if ($key != $day) continue;
$found_date = true;
// scan for store
foreach ($date as $item){
$found_store = false;
if ($item['store'] != $store) continue;
$found_store = true;
// stop looping if store found
break;
}
// create null element
if (!$found_store) {
$date []= array(
"store" => $store
, "price" => null
);
}
// stop looping if date found
break;
}
// if date not found, create all elements
if (!$found_date) {
$history[$day]= array(
0 => array(
"store" => $store
, "price" => null
)
);
}
print_r($history);
Before:
Array
(
[2016-05-28] => Array
(
[0] => Array
(
[store] => 1
[price] => 12
)
[1] => Array
(
[store] => 7
[price] => 18
)
[2] => Array
(
[store] => 9
[price] =>
)
)
)
After:
Array
(
[2016-05-28] => Array
(
[0] => Array
(
[store] => 1
[price] => 12
)
[1] => Array
(
[store] => 7
[price] => 18
)
[2] => Array
(
[store] => 9
[price] =>
)
[3] => Array
(
[store] => 8
[price] =>
)
)
)
Thanks to help from @trincot's comment I managed to get what I was trying to do using the store id as the key in the array, working code below.
$setPriceHistoryData = $daoObj->getSetPriceHistoryData($set['id']);
$chartDays = date('Y-m-d', strtotime('-30 days'));
$endDay = date('Y-m-d');
$priceHistoryData = array();
while ($chartDays <= $endDay) {
for ($i = 0; $i < count($setPriceData["price_history_store_data"]); $i++) {
$store = $setPriceData["price_history_store_data"][$i]["id"];
for ($j = 0; $j < count($setPriceHistoryData); $j++) {
if ($store == $setPriceHistoryData[$j]["vph_store"]
&& $chartDays == $setPriceHistoryData[$j]["vph_date"]
&& !isset($priceHistoryData[$chartDays][$store])) {
$priceHistoryData[$chartDays][$store] = $setPriceHistoryData[$j]["vph_price"];
} else {
if (!isset($priceHistoryData[$chartDays][$store])) {
$priceHistoryData[$chartDays][$store] = null;
}
}
}
}
// Increment day
$chartDays = date('Y-m-d', strtotime("+1 day", strtotime($chartDays)));
}
Since you're willing to change the data structure, a different, really cool approach could do the job with just a few simple lines of code. First change the data source to a new shape in which the store ID is the key and the price is the value
$history = [
'2016-06-15'=>[
1=>10, 2=>10, //On June 15, store 1 had price 10
],
'2016-06-16'=>[
1=>10, 3=>10,
],
'2016-06-17'=>[
3=>10, 4=>10,
],
];
Now all you have to do is cycle through the days in your source and add any missing stores using the +
operator on arrays (it adds missing keys)
$required_stores = [1,2,3,4]; // stores you wish to add if missing
//will be [1=>null, 2=>null, 3=>null, 4=>null]
$required_keys = array_combine(
$required_stores,
array_fill(0,count($required_stores),null)
);
//go through each day and add required keys if they're missing
foreach ($history as &$stores):
$stores += $required_keys
endforeach;
array_combined
returns an array by using the first parameter as keys and the second parameter as values.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.