php Optimize multiarray search - php

I am reading in a file with thousands of lines. I grab the id from each line and check to see if it is in a multiarray, that also has thousands of entries. If it is in the multiarray I need to have the key of the array it is in. I have this all working with the code shown below but it takes a very long time. I'm hoping someone can suggest a way to do it faster?
$array = [['id' => 'A202977', '550' => 0, '710' => 0],
['id' => 'A202978', '550' => 0, '710' => 0],
['id' => 'A202979', '550' => 0, '710' => 0]
];
$found = InMultiArray('A202978', $array);
$key = MultiArraySearch('A202978', $array);
echo 'Found '.$found .' at '.$key.'<br>';
//shows Found 1 at 1
function InMultiArray($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && InMultiArray($needle, $item, $strict))) {
return true;
}
}
return false;
}
function MultiArraySearch($needle, $haystack) {
foreach ($haystack as $key => $item) {
if (($needle == $item['id'])) {
return $key;
}
}
return FALSE;
}

You can safely and soundly cache the resulting resources into a JSON file, so next time when you need to load the data, you can just grab the content of the JSON file and pass it as a parameter to json_decode.
So, this is how you could proceed:
if the cached file does not exist or it is old, or it is older than the input file
proceed in the old and slow way
pass the result to json_encode and save it into a cache file
else
load the cache file's content
pass it as a parameter to json_decode and you have your result
Alternatively, you can use a database or even a cache-system, like Redis.

If you really need to find the index of the row by the ID field, you can create an associative array of IDs to array indices.
$array = [['id' => 'A202977', '550' => 0, '710' => 0],
['id' => 'A202978', '550' => 0, '710' => 0],
['id' => 'A202979', '550' => 0, '710' => 0]
];
// Array to map ID to array index in $dataRaw
$idIndexMap = [];
// Populate structs
foreach ($array as $i=>$currRow)
{
$idIndexMap[$currRow['id']] = $i;
}
$found = array_key_exists('A202978', $idIndexMap);
$key = $idIndexMap['A202978'];
echo 'Found ' . $found . ' at ' . $key . '<br>';
//shows Found 1 at 1
However if you just need to find the actual row by the ID, it's probably easier to just create an associative array that maps the ID to the actual row.
<?php
$array = [['id' => 'A202977', '550' => 0, '710' => 0],
['id' => 'A202978', '550' => 0, '710' => 0],
['id' => 'A202979', '550' => 0, '710' => 0]
];
// Array to map ID to array index in $dataRaw
$map = [];
// Populate structs
foreach ($array as $currRow)
{
$map[$currRow['id']] = $currRow;
}
$found = array_key_exists('A202978', $map);
$row = $map['A202978'];
echo 'Found ' . json_encode($row) . '<br>';

Related

How to sum column value or multiple values in multi-dimensional array?

How can I add all the columnar values by associative key? Note that key sets are dynamic and some key value is more than one.
Example array :
$myArray = array(
["apple" => 2,"orange" => 1,"lemon" => 4,"grape" => 5],
["apple" => 5,"orange" => 0,"lemon" => 3,"grape" => 2],
["apple" => 3,"orange" => 0,"lemon" => 1,"grape" => 3],
);
With single key value I can sum the column value easily with the code below.
$sumArray = array();
foreach ($myArray as $k => $subArray)
{
foreach ($subArray as $id => $value)
{
if (array_key_exists($id, $sumArray))
{
$sumArray[$id] += $value;
} else {
$sumArray[$id] = $value;
}
}
}
echo json_encode($sumArray);
the result will be like these:
{"apple":10,"orange":1,"lemon":8,"grape":10}
For multiple key values the code above is not working. How to sum column values if key value is more than one?
Example array:
$myArraymulti = array(
["apple" => 2,"orange" => 1,"lemon" => [4, 2],"grape" => 5],
["apple" => 5,"orange" => [0, 2],"lemon" => 3,"grape" => 2],
["apple" => 3,"orange" => 0,"lemon" => 1,"grape" => [3, 8]],
);
Desired result:
{"apple":10,"orange":3,"lemon":10,"grape":18}
Check if the value is an array. If it is, use the sum of the elements instead of the value itself when adding to the associative array.
foreach ($myArray as $k => $subArray)
{
foreach ($subArray as $id => $value)
{
if (is_array($value)) {
$value_to_add = array_sum($value);
} else {
$value_to_add = $value;
}
if (array_key_exists($id, $sumArray))
{
$sumArray[$id] += $value_to_add;
} else {
$sumArray[$id] = $value_to_add;
}
}
}
I suggest you fix your data structure, though. You should just make every value an array, rather than mixing singletons and arrays, so you don't have to use conditionals in all the code that processes the data.
$keys = [];
forEach($myArraymulti as $array){
$keys = array_merge(array_keys($array), $keys);
}
$res = [];
forEach(array_unique($keys) as $key){
forEach($myArraymulti as $array){
if(isset($array[$key])){
$res[$key] = (isset($res[$key]) ? $res[$key] : 0) +
(is_array($array[$key]) ? array_sum($array[$key]) : $array[$key]);
}
}
}
$res = json_encode($res));

Foreach Json Array

I have array, where get_# have random number. Need to foreach all items [result][result][get_#RAND_NUM#] and take [id], [name].
Thanks!
Array:
-[result]
--[result]
---[get_1]
----[id] = "1"
----[name] = "dog"
---[get_6]
----[id] = "53"
----[name] = "cat"
According to PHP manual the foreach makes an iteration over array or object. foreach provides $key and $value options. From this $key var you can get the random number you expect.
The foreach construct provides an easy way to iterate over arrays. foreach works only on arrays and objects, and will issue an error when you try to use it on a variable with a different data type or an uninitialized variable.
$data = ['result' => [
'result' => [
'get_1' => ['id' => 1, 'name' => 'doc'],
'get_6' => ['id' => 2, 'name' => 'cat'],
]
]];
$new_data = [];
foreach ($data['result']['result'] as $key => $val) {
// If you want to get the random number uncomment the below line
// $random_no = explode('_', $key)[1]; echo $random_no;
echo "For key {$key}, id = {$val['id']} and name = {$val['name']} </br>";
$new_data[] = ['id' => $val['id'], 'name' => $val['name']];
}
print '<pre>';
print_r($new_data);
Demo

Loop Array in PHP

how to loop an array if the data is 1 or more than 1?
I tried it with
foreach($array['bGeneral'] as $item) {
echo $item['bItem'];
}
but for arrays that have 1 data an error
Basically you need to check if the first element of $array['bGeneral'] is an array or a data value, and if so, process the data differently. You could try something like this:
if (isset($array['bGeneral']['bItem'])) {
// only one set of values
$item = $array['bGeneral'];
// process item
}
else {
// array of items
foreach ($array['bGeneral'] as $item) {
// process item
}
}
To avoid duplication of code, you will probably want to put the item processing code in a function.
Alternatively you could create a multi-dimensional array when you only have one value and then continue processing as you do with multiple values:
if (isset($array['bGeneral']['bItem'])) {
$array['bGeneral'] = array($array['bGeneral']);
}
foreach ($array['bGeneral'] as $item) {
// process item
}
Don't forget recursion - sometimes it is a best choise :
function scan_data($data, $path = null) {
if (!is_array($data))
echo "{$path} : {$data}\n";
else
foreach ($data as $k => $v)
scan_data($v, $path . '/' . $k);
}
$data = [
['a' => 1, 'b' => 2],
['a' => ['c' => 3, 'd' => 4], 'b' => 5],
['a' => 1, 'b' => ['e' => ['f' => 1, 'g' => 2], 'h' => 6] ]
];
scan_data($data);
Output:
/0/a : 1
/0/b : 2
/1/a/c : 3
/1/a/d : 4
/1/b : 5
/2/a : 1
/2/b/e/f : 1
/2/b/e/g : 2
/2/b/h : 6

Recursively check value empty or not

I have to check if items with keys 2, 3, 4, 5 in the sub array with index 0 are empty or not. If empty, I need to throw an exception.
If not empty, then move to next iteration, checking items with keys 3, 4, 5, 6 in the sub array with index 1, and so on.
Items with keys 0 and 1 will always be empty so nothings need to be done with them.
So, check for items with key > 1 then 4-4 pair check if anyone is empty and then throw an exception.
here is my code
$array = array(
array('0' => '','1' => '','2' => 'Wasatch standard','3' => 'Wasatch standard','4' => '3,5,2','5' => 'English','6' => '','7' => '','8' => ''),
array('0' => '','1' => '','2' => '','3' => 'ThisIsAtest','4' => 'Wasatch standard1','5' => '3,4,5','6' => 'English','7' => '','8' => ''),
array('0' => '','1' => '','2' => '','3' => '','4' => 'Wasatch standard1.1','5' => 'Wasatch standard1.1','6' => '2','7' => 'Mathematics','8' =>''),
);
for($i=0;$i<count($array);$i++){
checkRecursivelyIfEmpty($array[$i],array('2'+$i,'3'+$i,'4'+$i,'5'+$i));
}
function checkRecursivelyIfEmpty($value,$sumValue){
foreach ($sumValue as $k => $v) {
if(empty($value[$v])){
throw new Exception("Error Processing Request");
}
}
}
The following function first checks whether the input is an array indeed, then checks for the indexes to be empty. If not, then it throws an exception. Furthermore, it traverses the array to see if there are inner arrays. If so, then it recursively checks them as well. After the function there is a quick demonstration of usage.
function checkThings($inputArray, $subArray) {
//If it is not an array, it does not have the given indexes
if (!is_array($inputArray)) {
return;
}
//throws exception if one of the elements in question is not empty
foreach ($subArray as $key) {
if ((isset($inputArray[$key])) && (!empty($inputArray[$key]))) {
throw new Exception("My Exception text");
}
}
//checks for inner occurrences
foreach ($inputArray as $key => $value) {
if (is_array($inputArray[$key])) {
checkThings($inputArray[$key], $subArray);
}
}
}
//Calls checkThings for all elements
for ($index = 0; $index < count($myArray); $index++) {
checkThings($myArray[$index], array($index + 2, $index + 3, $index + 4, $index + 5));
}
Use foreach and check using empty($value)
foreach ($array as $key => $value) {
$value = trim($value);
if (empty($value))
echo "$key empty <br/>";
else
echo "$key not empty <br/>";
}
Assuming the array is named $a you can use this code. The outer loops iterates over all the arrays. The inner loop iterates from $i+2 to $i+5 (in the case of $i=0, you get 2, 3, 4 and 5) on the sub arrays. The function empty() checks that the item is set and not equal to false (for instance, an empty string).
for($i=0; $i<count($a); $++)
for($j=$i+2; $j<$i+6; $j++)
if(empty($a[$i][$j]))
//Raise an error!

Sum values in array and simplify key names

This is almost similar to my other question which is related to the same project I'm working on.. Link to my other question
but in this case the array is different as follow:
Array
(
[2014-08-01 11:27:03] => 2
[2014-08-01 11:52:57] => 2
[2014-08-01 11:54:49] => 2
[2014-08-02 11:59:54] => 4
[2014-08-02 12:02:41] => 2
[2014-08-05 12:09:38] => 4
[2014-08-07 12:23:12] => 3
[2014-08-07 12:25:18] => 3
// and so on...
)
That is my output array and in order to get that array I had to do some miracles... anyway, so based on that array I have to sum the value for each key date and build an array something like this...
Array
(
[2014-08-01] => 6
[2014-08-02] => 6
[2014-08-05] => 4
[2014-08-07] => 6
// and so on...
)
That last array will be use to build graphs with morrisonJS, what I have is this:
$res_meno = array();
foreach ($sunArr as $keys => $values) {
$arrays= explode(" ",$sumArr[$keys]);
$res_meno[] = $arrays[0];
}
$vals_char2 = array_count_values($res_meno);
That is my attempt to build my last array but is not working...
any help would be greatly appreciated!
Thank you for taking the time.
Try this code
<?php
$arr = array(
"2014-08-01 11:27:03" => 2,
"2014-08-01 11:52:57" => 2,
"2014-08-01 11:54:49" => 2,
"2014-08-02 11:59:54" => 4,
"2014-08-02 12:02:41" => 2,
"2014-08-05 12:09:38" => 4,
"2014-08-07 12:23:12" => 3,
"2014-08-07 12:25:18" => 3
);
$new_array = array();
foreach($arr as $k => $v){
$date = reset(explode(" ", $k));
if(isset($new_array[$date])){
$new_array[$date] += $v;
}
else{
$new_array[$date] = $v;
}
}
print_r($new_array);
?>
DEMO
$sunArr = array
(
"2014-08-01 11:27:03" => 2,
"2014-08-01 11:52:57" => 2,
"2014-08-01 11:54:49" => 2,
"2014-08-02 11:59:54" => 4,
"2014-08-02 12:02:41" => 2,
"2014-08-05 12:09:38" => 4,
"2014-08-07 12:23:12" => 3,
"2014-08-07 12:25:18" => 3,
);
$res_meno = array();
foreach ($sunArr as $keys => $values) {
$arrays= explode(" ",$keys);
if(isset($res_meno[$arrays[0]]))
{
$res_meno[$arrays[0]] = $res_meno[$arrays[0]] + $values;
}
else
{
$res_meno[$arrays[0]] = $values;
}
}
print_r($res_meno);
exit;
Try this, i think it might fix the problem
Try this PHP Code You Can test here
$sunArr = Array
(
'2014-08-01 11:27:03' => 2,
'2014-08-01 11:52:57' => 2,
'2014-08-01 11:54:49' => 2,
'2014-08-02 11:59:54' => 4,
'2014-08-02 12:02:41' => 2,
'2014-08-05 12:09:3' => 4,
'2014-08-07 12:23:12' => 3,
'2014-08-07 12:25:18' => 3
);
$key = 0;
$res_meno = array();
foreach ($sunArr as $keys => $values)
{
$ar= explode(" ", $keys);
if( $key == $ar[0] )
{
$res_meno[$key] = $sunArr[$keys] + $res_meno[$key];
}
else
{
$key = $ar[0];
$res_meno[$key] = $values;
}
}
echo '<pre>';
print_r($res_meno);
die;
Where does the first array come from? If it's from a SQL database, it's better to create a query that returns the aggregated array.
Otherwise no need to use array_key_values for that:
$res_meno = array();
foreach ($sumArr as $keys => $values) {
$key = substr($keys, 0, 10);
$res_meno[$key] = (empty($res_meno[$key]) ? 0 : $res_meno[$key]) + $values;
}
Here is a solution which uses a callback. Not to use loops is often better!
$sunArr = array(
'2014-08-01 11:27:03' => 3,
'2014-08-01 11:27:05' => 5,
'2013-09-01 11:01:05' => 1
);
$res = array();
function map($item, $key, &$result)
{
$result[current(explode(" ", $key))] += $item;
}
array_walk($sunArr, "map", &$res);
var_dump($res);
You can test it here on codepad.

Categories