I have an array of numbers that I need to search through a multidimensional array for.
I have a thousand records of songs. Each song has an array of float values that I need to search through, and I'll need to retrieve the songs if the first digits of each float value match any float number in my array.
So for example my array of numbers I need to find are:
array(14, 18.12, 12.1290, 55.01)
and the songs are sorted in a json file like so:
{"id": 129112, "name": "XYZ Song", "values": { 14.1290, 55.0192, 129 } }
Currently my for loops are taking too long to loop through all the records.
I think I need to sort through the values with a preg_match function and the right pattern (except I'm terrible with regex), what do you guys think?
Please check this code. This code may help you
<?php
// PHP program to carry out multidimensional array search
// Function to recursively search for a given value
function multi_array_search($search_value, $array, $id_path) {
if(is_array($array) && count($array) > 0) {
foreach($array as $key => $value) {
$temp_path = $id_path;
// Adding current key to search path
$temp_path[] = $value;
// Check if this value is an array
// with atleast one element
if(is_array($value) && count($value) > 0) {
$res_path = multi_array_search(
$search_value, $value, $temp_path);
}
else if($value == $search_value) {
print_r($temp_path);
}
}
}
}
// Multidimensional (Three dimensional) array as suggested by you
$songs_array= array(
0 => array(
"id" => "129112",
"name" => "X Song",
"value" => array( 14.1290, 329, 129 )
),
1 => array(
"id" => "129113",
"name" => "XY Song",
"value" => array( 14.1291, 55.0192, 229 )
),
2 => array(
"ic" => "129114",
"name" => "XYZ Song",
"value" => array( 14.1292, 55.0193, 388 )
)
);
$songs= multi_array_search('329', $songs_array, array());
?>
Here I have searched for 329 in $song_array and
Result is :
Related
I have this PHP array:
$this->user_list = array( 0 => 'Not paid',1 => 'Not paid', 2 => 'Not paid', 7 => 'Waiting, 15 => 'Waiting', 10 => 'Cancelled' );
How can I simplify this array as the id numbers are different, but some of them have same status?
I tried it like this:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
but it doesn't work as expected.
Basically I want to achieve this:
echo $this->user_list[15] should give me Waiting, echo $this->user_list[10] should give me Cancelled, etc. So this is working in my first array very well, I am just thinking about grouping duplicate names there.
As mentioned by other contributors, there is no native support in the PHP grammar for your intended use case. As clearly stated in the PHP: Arrays documentation:
An array can be created using the array() language construct. It takes any number of comma-separated key => value pairs as arguments.
So basically each element in an array is a key => value pair, which means you cannot associate multiple keys to a single element.
This also explains why your first tentative didn't work:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
If you don't specify a key for an element, PHP uses a progressive index (0, 1, ...). So basically in the example above, the first zero is not actually a key, but a value, and PHP binds it to the key = 0. Maybe it could be easier for you to understand how it works if you print a var_dump or print_r of $this->user_list. You would get something similar to the following structure (NOTE: I have simplified the structure to make it more clear):
[
0 => [
0 => 0
1 => 1
2 => "Not paid"
],
1 => [
0 => 7,
15 => "Waiting"
],
10 => "Cancelled"
]
So how do we resolve this problem? Well... actually there is no need to contort the structure by swapping keys with values as other contributors seem to suggest. Changing the structure might simplify your "data entry" work but might also create big issues in other parts of the program because who knows, maybe accessing the invoice data by "ID" is simply more efficient than by "status" ... or something.
Since PHP does not provide such a feature out of the box, I believe a better solution would be to develop our own function; a good starting point could be the one in the example below.
function explode_array($config, $sep = ',') {
$res = [];
foreach($config as $configKey => $value) {
// split key values
$keys = explode($sep, $configKey);
foreach($keys as $key) {
$res[$key] = $value;
}
}
return $res;
}
$config = [
'0,1,2' => 'Not paid',
'7,15' => 'Waiting',
'10' => 'Cancelled'
];
$myArr = explode_array($config);
print_r($myArr);
The idea is quite simple: since we cannot use an array as key we leverage the next best data type, that is a CSV string. Please note there is no error handling in the above code, so the first thing you may want to do is adding some validation code to the explode_array (or however you wish to name it) function.
you should use like this. if id number is invoice id or something else and other value is there status about it.
$arr = array(
'Not paid' => [0,1,2] ,
'Waiting' => [5,6],
'Cancelled' =>[8]
);
foreach($arr as $key => $val){
foreach($val as $keys => $vals){
echo "invoiceid ".$vals ." status ".$key;
echo"<br>";
}
}
// for only one status you can use like this
foreach($arr['Not paid'] as $key => $val){
echo $val;
echo"<br>";
}
just try to run this and check output.
PHP has no built-in function or structure for handling cases like this. I'd use a simple array value-cloning function to map your duplicates. Simply have one instance of each status, then map the aliases, and then run a function that clones them in. As follows:
// Status list:
$ulist = [ 0 => 'Not paid', 7 => 'Waiting', 10 => 'Cancelled' ];
// Alternative IDs list, mapped to above source IDs:
$aliases = [ 0 => [1,2], 7 => [15] ];
// Function to clone array values:
function clone_values(array &$arr, array $aliases)
{
foreach($aliases as $src => $tgts) {
foreach($tgts as $tgt) {
$arr[$tgt] = $arr[$src];
}
}
ksort($arr); // If the order matters
}
// Let's clone:
clone_values($ulist, $aliases);
This results in the following array:
array(6) {
[0] · string(8) "Not paid"
[1] · string(8) "Not paid"
[2] · string(8) "Not paid"
[7] · string(7) "Waiting"
[10] · string(9) "Cancelled"
[15] · string(7) "Waiting"
}
....which can be accessed as you expect, here $ulist[2] => Not paid, etc. If the use case is as simple as illustrated in the OP, I'd personally just spell it out as is. There's no dramatic complexity to it. However, if you have dozens of aliases, mapping and cloning begins to make sense.
As said in the comments, you can't have multiple keys with one value. The best way is to use the keyword => [ number, number, number...] construction.
//set a result array
$result = [];
//loop the original array
foreach ( $this->user_list as $number => $keyword ){
//if the keyword doesn't exist in the result, create one
if(!isset ( $result [ $keyword ] ) ) $result[ $keyword ] = [];
//add the number to the keyword-array
$result[ $keyword ] [] = $number;
}
There are two arrays:
$arr1 = [
"Value1",
"Value2",
"Value1"
];
$arr2 = [
["key_1" => "5", "key_2" => "10"], // relates to Value1
["key_1" => "2", "key_2" => "4"], // relates to Value2
["key_1" => "50", "key_2" => "100"] // relates to Value1
];
I cannot simply combine the two arrays because the duplicated values in $arr1 will lead to overwritten data from $arr2.
The behavior that I need is for subarray data to be added if a value from $arr1 is encountered more than once.
I tried to find all sorts of folding options while searching the web, but I could find anything that was right.
I need this output from the sample input arrays:
array (
'Value1' =>
array (
'key_1' => 55,
'key_2' => 110,
),
'Value2' =>
array (
'key_1' => '2',
'key_2' => '4',
),
)
I've tried to write a solution, but I'm not really sure how to tackle the problem.
foreach ($items as $item) {
if (isset($bal[$item['bonus_name']])) {
//Here I don't know how to sum a new one to the repetition?
} else {
$bal[$item['bonus_name']] = $item['bonus_count'];
}
}
Whatever I try, there's no way to sum a repetitive array of elements. I need some help.
Loop the first array to declare the index -> group relationship.
Check if the currently encountered group is unique to the output array. If so, push the entire subarray from the corresponding index in the second array into the output array as the initial values of the group.
If the group is encountered more than once, add each column value to the related amount in the group's subarray.
Code: (Demo)
$result = [];
foreach ($arr1 as $index => $group) {
if (!isset($result[$group])) {
$result[$group] = $arr2[$index];
} else {
foreach ($arr2[$index] as $key => $value) {
$result[$group][$key] += $value;
}
}
}
var_export($result);
So I have the following array of data in PHP
$array = array(
"animal" => "panda",
"location" => "San Diego",
"age" => "2",
),
array(
"animal" => "tiger",
"location" => "Bronx",
"age" => "5",
),
array(
"animal" => "panda",
"location" => "Bronx",
"age" => "3",
),
array(
"animal" => "tiger",
"location" => "bronx",
"age" => "3",
),
array(
"animal" => "panda",
"location" => "San Diego",
"age" => "2",
)
)
What I want to do is convert this into an associative array that will contain the count for the animals, locations and age. so if I wanted to see how many pandas are in san diego and are age 2 I would access the new array with $newArray['panda']['San Diego']['2'] and the output would be 2.
My issue is I can easily run a loop and build an array and count the items when it is completely static like so.
foreach($array as $a) {
$newArray[$a['animal']][$a['location']][$a['age']] += 1;
}
However I want to know how to accomplish the same concept when the number of keys is dynamic. for instance what if there are only location and animal in one call and sometimes there might be location, animal, age, and gender in another call.
There are some examples I have found that expound on doing this for associative arrays but not for multidimensional arrays with this particular use case.
Any Thoughts?
The Idea
It looks to me as if you're trying to do too much in one go. Instead of transforming your array to contain all your answers, consider making a function to run queries against it.
The Solution
/**
* #param array $animals The whole animals array
* #param array $query Array containing keys and values you want to filter by
*
* #return array Animals that match $query
*/
function filterAnimals($animals, $query) {
return array_filter($animals, function ($animal) use ($query) {
// Check if $animal has every key and the corresponding value from $query
foreach ($query as $key => $value) {
if (!isset($animal[$key]) || $animal[$key] != $value) {
return false;
}
}
return true;
});
}
filterAnimals() filters your $animals array and returns only the animals that have the common keys and values with the $query array. Searching for all pandas from San Diego would look like this:
$result = filterAnimals($animals, [
'animal' => 'panda',
'location' => 'San Diego'
]);
Then, if you wish, you can count the $result:
$count = count($result);
I need some help wrapping my head around a problem. I have an array filled with other arrays. I need to:
Loop through the entire array and build a new array called finalOptions
Each iteration of the loop will take a new SearchIndex and apply the other paramenters
i.e
SearchIndex => SportingGoods
MinPercentageOff => 50
MinimumPrice => 1
ItemPage => 1
Sort => salesrank
BrowseNode => 2342470011
THEN:
Final array should contain data like this
SearchIndex => SportingGoods
MinPercentageOff => 60
MinimumPrice => 100
ItemPage => 2
Sort => salesrank
BrowseNode => 3403201
Basically, I'm creating a new array and sending it to another method that will execute a call to an API and return a result, then doing it again until my array options are complete.
This might not be the way to go and I'm looking for suggestions/pseudo code on an approach. Here is the basics of what I have so far:
Starting with this code
$allOptions = array(
"SearchIndex" => array("SportingGoods", "Tools"),
"MinPercentageOff" => array("50", "60", "70"),
"MinimumPrice" => array("1", "100", "1000"),
"ItemPage" => array("1", "2"),
"Sort" => array("salesrank")
"BrowseNode" => array(
"SportingGoods" => array("2342470011", "3403201"),
"Tools" => array("511364")
)
)
$finalOptions = array();
foreach($allOptions as $options){
foreach($options["SearchIndex"] as $searchIndex){
$finalOptions[] = "SearchIndex" => $searchIndex[]
}
$this->itemSearch($finalOptions);
}
EDIT
The arrays will contain more values. i.e "ItemPage" => array("1", "2"), will have 1 - 10. The others will have more values as well.
From the given array it will produce 54 possible combinations as you described.
Also you need to make sure you have array in $allOptions['BrowseNode'] indexed as each value of $allOptions['SearchIndex']. Otherwise it will produce error.
Cartesian function from here.
$allOptions = [
"SearchIndex" => ["SportingGoods", "Tools"],
"MinPercentageOff" => ["50", "60", "70"],
"MinimumPrice" => ["1", "100", "1000"],
"ItemPage" => ["1", "2"],
"Sort" => ["salesrank"],
"BrowseNode" => ["SportingGoods" => ["2342470011", "3403201"], "Tools" => ["511364"] ] ];
$finalOptions = $allOptions; // copy our initial $allOptions array
unset($finalOptions['BrowseNode']); // deal with BrowseNode key later with custom iterator
$cartesian_product = cartesian($finalOptions); // find cartesian except BrowseNode
foreach($cartesian_product as $cartesian) // each member of cartesian product will iterate here
{
foreach($allOptions['BrowseNode'][$cartesian['SearchIndex']] as $possible)
/*
We have unset the BrowseNode, so need to refer original $allOptions array for BrowseNode,
In every cartesian product, we will get $cartesian['SearchIndex'] and it will contain either
'SportingGoods' or 'Tools' , so in our original array, look for 'BrowseNode' value, having key
same as $cartesian['SearchIndex'].
$allOptions['BrowseNode'][$cartesian['SearchIndex']] <---- is similar to below two lines
$key = $cartesian['SearchIndex'];
$allOptions['BrowseNode'][$key];
Finally iterate through $allOptions['BrowseNode'][$cartesian['SearchIndex']] will iterate as many times,
as many values there are
*/
{
$cartesian['BrowseNode'] = $possible; // assign the long waited key here to 'BrowseNode'
var_dump($cartesian); // here you can do $this->itemSearch($cartesian);
}
}
function cartesian($input) {
$input = array_filter($input);
/*
will renove any false values in input array,
in our array's case, it will do nothing.
*/
$result = [[]];
foreach ($input as $key => $values) {
$append = [];
foreach($result as $product) {
foreach($values as $item) {
$product [$key] = $item;
$append [] = $product;
}
}
$result = $append;
}
return $result;
}
I have the following PHP multidimensional array, I'm looking to try select 4 random items and then show them with the title, image and text. With the code I've used I seem to get a single number which is randomized and not what I need.
<?php
$arr = array(
array(
"image" => "",
"title" => "Open 7 days.",
"text" => "We’re open 7 days a week."
),
array(
"image" => "",
"title" => "Well done",
"text" => "Well done you done great."
),
array(
"image" => "",
"title" => "Rice",
"text" => "Various flavours"
),
array(
"image" => "",
"title" => "Rooms",
"text" => "Roomy rooms for a roomyful time"
),
array(
"image" => "",
"title" => "Keep in touch.",
"text" => "Stay in touchwith us as we'll miss you"
),
array(
"image" => "",
"title" => "Location",
"text" => "We'll show you where we are."
),
array(
"image" => "",
"title" => "The Home",
"text" => "See our home page"
)
);
print_r(array_rand($arr));
If you're picking only one entry, array_rand() returns a single key for a random entry. If you use the num to specify how many keys should be picked, then it returns num number of keys of random entries.
The function only returns the keys of the random entries and not the array chunks itself. You'll have to manually build the array from the returned keys:
// get the random keys
$keys = array_rand($arr, 4);
// initialize result array
$result = array();
// loop through the keys and build the array
foreach ($keys as $k) {
$result[] = $arr[$k];
}
print_r($result);
Update
From a quick benchmark, it seems array_rand() is signficantly faster than using shuffle() for larger arrays. The benchmark was done on an array having 14336 elements with 10000 iterations each.
The results obtained on my dev machine were as follows:
Number of elements in the array - 14336
Number of iterations for each method - 10000
array_rand() version took 4.659 seconds
shuffle() version took 15.071 seconds
The code used for benchmarking can be found in this gist.
No need to loop !
shuffle() and array_slice() does the job.
Simply shuffle your array such that it rearranges the entries , now pick the first 4 items using array_slice.
shuffle($arr);
print_r(array_slice($arr,0,4));
Demo
Read about the $num parameter array_rand()
print_r(array_rand($arr, 4));
To display all:
foreach(array_rand($arr, 4) as $key) {
echo $arr[$key]['text'] ."\n";
//etc
}