Selectively flattening a PHP array according to parent keys - php

I need to selectively flatten an array in PHP, but do it selectively. If a key matches a pattern then all sub elements below that key should be included in the 'flat' output.
SO If I had a catalogue of music:
=> array of albums => each of which is an array of song titles
Then I could search for a string, and would get a flat array in reponse. SO if I searched for 'sun' then I would get the entire catalogue for any artist with 'sun' in their name, plus the albums for other artists where 'sun' was in the album name.
Hopefully that makes sense.
Anyone got any thoughts?

Is there a reason you're not using a database to store what sounds like a significant amount of info? It would be fairly simple to write a query in SQL to pull the data out that you want.

Ok, I'm going to assume your data looks like this:
$data = array(
"Bill Withers" => array (
"Lovely Day",
"Use Me",
"Ain't No Sunshine"
),
"Fleet Foxes" => array (
"Sun It Rises",
"White Winter Hymnal"
),
"Billy Joel" => array (
"Piano Man"
)
);
...and that given the input "Bill", you want the output: ["Lovely Day", "Use Me", "Ain't No Sunshine", "Piano Man"]. Here's one way you could do it.
function getSongs($data, $searchTerm) {
$output = array();
foreach ($data as $artist => $songs) {
if (stripos($artist, $searchTerm) !== false)) {
$output = array_merge($output, $songs);
}
}
return $output;
}
...I'll also assume you've got a good reason to not use a database for this.

Do you mean something like that?
$a = array(
"Sunny" => "Bla-bla1",
"Sun" => "Bla-bla2",
"Sunshine" => "Bla-bla3",
);
foreach ($a as $k => $v)
{
// check here whenever you want for $k
// apply something to $v
if ( ... )
$b[$i++] = $v;
}

$sample_data = array(
'artist_name' => array(
'album_name' => array(
'song_name',
'other_mp3_id_info'
)
)
);
function s2($needle,$haystack) {
$threads = array();
foreach ($haystack as $artist_name => $albums) {
if (stripos($artist_name, $needle) !== false)) {
$threads[] = $haystack[$artist_name]; //Add all artist's albums
} else {
foreach ($albums as $album_name => $songs) {
if (stripos($album_name, $needle) !== false)) {
$threads[$artist_name][] = $haystack[$album_name]; //add matching album
}
}
}
}
return $threads;
}

To build off NickF's work, assuming your data looks like his, I'd write the function this way.
function getSongs($data, $searchTerm) {
foreach ($data as $artist => $songs) {
if (stripos($artist, $searchTerm) !== false)) {
$output[$artist] = $songs;
}
}
return $output or null;
}
The results of this function, when no matches are found will obviously return null instead of a blank array; when several matches are found they will then be grouped by their artist. I find direct assignment, $output[$artist] = $songs, to provide more predictable results than array_merge in my own experience. (This also preserves the artist for outputting that data.)
Like NickF said, I would assume you've good reason to not do this with a database? SQL for this would be very simple, such as,
SELECT artist, song FROM songs WHERE artist LIKE '%Bill%' GROUP BY artist;

You can use preg_grep for the searches, be sure to sanitize the input, though:
$matchingArtists = preg_grep('/' . preg_quote($searchString) . '/', array_keys($data));
$matchingSongs = array();
foreach ($data as $artist => $songs) {
$matchingSongs = array_merge($matchingSongs, preg_grep('/' . preg_quote($searchString) . '/', $songs));
}

Related

Very Complex SQL Data Result Merge via PHP (Multi Dimentional Arrays)

Sorry, I have a hard time to write proper thread title for this problem.
Here's my question:
In short: How to merge array item and calculate.
Here's the full explanation
1) I have a (WP custom) database to track statistics: visits, unique visits, etc, and it's stored per post per date.
To make it easier to understand. Here's the screenshot of the table:
2) This is the example data when I queried it:
https://gist.github.com/turtlepod/8e7dc93bae7f0b665fd5aea8a9694998
So in this example we have multiple post ID: "90", "121", & "231"
We have multiple date in db: "2017-03-20", "2017-03-21", "2017-03-22"
We have multiple stats: "visits", and "unique_visits"
We also have a "stat_value" for each item.
Each item have unique ID.
All data is dynamically created when an event happen. so not all post_id have 2 stats or the above date.
Note: keep in mind that in real code, we have a lot more data and variations than the example above.
3) I need to merge the data:
The post_id "121" is the same as post "231", so we need to merge and add the "stat_value" into one data and remove "231" entry.
What is the best way to do this (dynamically) via PHP ?
I have this data:
$raw_data = array( ... ); // the one in github gist
$post_groups = array(
'121' => array( '121', '231' ), // main post_id => array of alias.
);
It need to return the same data format as $raw_data, but remove the data of "231" and include/sum the "stat_value" of "231" to "121".
Thank you.
Try it with this:
function david_transform_data($data, $groups) {
if (empty($groups) === true) {
return $data;
}
// Transform groups into a more useful format
$transformed_groups = array();
foreach ($groups as $post_id => $aliases) {
foreach ($aliases as $alias) {
if (absint($post_id) === absint($alias)) {
continue;
}
$transformed_groups[absint($alias)] = $post_id;
}
}
// Replace aliases with the real post id
foreach ($data as $index => $stat) {
if (isset($transformed_groups[absint($stat->post_id)]) === false) {
continue;
}
$data[$index]->post_id = $transformed_groups[absint($stat->post_id)];
}
// Go through stats and merge those with the same post_id, stat_id
// and stat_date
$merged_stats = array();
$index_tracker = 0;
$stats_hash = array();
foreach ($data as $index => $stat) {
$hash_key = sprintf(
'%s-%s-%s',
$stat->post_id,
$stat->stat_id,
$stat->stat_date
);
if (isset($stats_hash[$hash_key]) === true) {
$merged_stats[$stats_hash[$hash_key]]->stat_value += absint($stat->stat_value);
continue;
}
$merged_stats[] = $stat;
$stats_hash[$hash_key] = $index_tracker;
$index_tracker++;
}
return $merged_stats;
}
var_dump(david_transform_data($raw_data, $post_groups));
There might be a faster solution but this is the first thing that came to my mind.

What the best way to determine if a string is present in one of 5 array?

I got a marker with a category, say : "luggage" i would like to know what parent categories is luggage to set a specific marker on a map.
I created a top categories list of each category i need to display. Something like :
$education = [ "adultedu", "collegecounseling", "collegeuniv", "educationservices", "elementaryschools", "highs|chools", "preschools", "privatetutors", "religiousschools", "specialed", "specialtyschools", "artschools", "cprclasses", "cookingschools", "cosmetology_schools"]
I got the same lists for transports, shopping, health etc...
What is the best way to search in which category my keyword is from ?
Use an array and iterate through while using in_array:
$arrays = array(
'education' => &$education,
'transport' => &$transport,
'shopping' => &$shopping,
'health' => &$health
);
$searchingFor = 'foo';
$searchingForCategory = null;
foreach ($arrays as $category => $array) {
if (in_array($searchingFor, $array)) {
$searchingForCategory = $category;
break;
}
}
var_dump($searchingForCategory); //education / transport / shopping / health / NULL
You have to check each array with in_array() function.
if (in_array('luggage', $education)) {
// found
}
Also you can add all top categories to one array, lets say $topCategories ;)
Then you can check all with simple loop:
$foundInCategory = '';
foreach ($topCategories as $name => $subCategories) {
if (in_array('luggage', $subCategories)) {
$foundInCategory = $name;
break;
}
}
It'll add category name in which subcategory was found to variable $foundInCategory.

Array search to return similar array key

I am not sure what should be title of this question, If you have better option, don't hesitate to change.
I need to search in an array with team's full name and return the short name. Now I have the following creteria:
$teams = array('MMB' => 'Mumbai', 'MMB' => 'Mumbai Indians');
$Vteam = (array_search($vteam, $teams, true) !== false) ? array_search($vteam, $teams) : substr($vteam, 0, 3);
When I search for 'Mumbai Indians', it returns 'MMB', but when I search for 'Mumbai' alone it returns 'Mum'.
I have around 50 team names in $team array.
How should I code so that on 'Mumbai' and 'Mumbai Indians' search it returns me 'MMB' always?
Any help would be really appreciated.
If you're creating the $teams array by yourself, then form it properly with an array for the values!
$teams = array('MMB' => array( 'Mumbai', 'Mumbai Indians'));
However, if you want a lookup of the short name, invert this design:
$teams = array( 'Mumbai' => 'MMB', 'Mumbai Indians' => 'MMB');
Now, if you want to know Mumbai's short name, just index the array on their name:
echo $teams['Mumbai']; // Output: MMB
echo $teams['Mumbai Indians']; // Output: MMB
If you are doing partial match you will probably need to use a foreach loop:
$search = 'Mumbai';
$team = '';
foreach($teams as $shortname => $longname) {
if(strpos($longname,$search) !== false) {
$team = $shortname;
break;
}
}

Searching for parts of string in multi level array

Is there a function that allows me to search inside a multidimensional array that goes multiple levels deep? An example of an array can be found below.
What I want is to be able to search in the entire array, regardless of how deep it goes (3 levels deep would be the practical limit though). The search must be done in all of the strings inside the array elements, and to make it even more complex, it needs to be able to find parts of a string in the array (preferably case insensitive).
I've searched for a good class or function that can handle this in a fast and efficient way, but haven't found one so far.
Array
(
[0] => Array
(
[OrderReferenceNumber] => 201100196
[OrderCustomerID] => 01239123
[OrderCustomerName] => test
[OrderHistoryItems] => Array
(
[0] => Array
(
[OrderItem] => productID
[OrderItemGroup] => productName
)
)
)
Much appreciated!
This will search all elements on all levels of the array, and the search is case sensitive. Just pass the search term and the array to search.
class mySearcher
{
protected $search = '';
public function search($search, $arr)
{
$this->search = $search;
$this->searchArr($arr);
}
protected function searchArr($arr)
{
if(is_array($arr))
{
foreach($arr as $value)
{
if(is_array($value))
{
$this->searchArr($value); // this element is an array, so recursively search it
}
else
{
if(stripos($value, $this->search) !== false)
{
// found the search term, do something
echo 'found in: ' . $value . '<br />';
}
}
}
}
}
}
$obj = new mySearcher();
$obj->search('test', $arr); // search for 'test' in the array called $arr

PHP show if with different categories array or variable?

Having some problems here, I think I am just overlooking something really simple...
I have a CMS that have multiple categories.
How do I create a variable or array that has the included categories groups that I want to use in my SHOW IF STATEMENT ??
So for example:
<?php
$catsrow = array(
'cat_1' => '41','46','62',
'cat_2' => '41','45','63',
'cat_3' => '41','43','65'
);
?>
<?php if
(catsrow[0] || catsrow[1] || catsrow[2]) == ($row_DetailRS1['category'])
{ echo 'do work' }
else { ?>
Thanks in advance!!
I guess what I am asking is, how do I compare an array with multiple groups inside. I need to compare different grouped categories..
Like $catsArray = ARRAY(cat_1 => '2,3,4' , cat_2 => '5,6,7' , cat_3 => '8,9,10')
if $row['cat_from_page'] == $catsArray (any of the groups) then SHOW THIS { }
????
you may need to explode the parts of the array
Kinda like $parts = explode(',' , $cat);
http://php.net/manual/en/function.explode.php
but you will need to implode the whole thing into one array
Like implode (',', $parts);
http://php.net/manual/en/function.implode.php
My Best guess at what you're trying to do:
$categories = array(
'cat_1' => array(
'41','46','62'
),
'cat_2' => array(
'41','45','63'
),
'cat_3' => array(
'41','43','65'
)
);
$row_DetailRS1['category'] = '41';
foreach($categories as $category => $items) {
foreach($items as $item) {
if($row_DetailRS1['category'] == $item) {
echo "Item: ".$item." found in Category: ".$category."\n";
}
}
}

Categories