Selective alignment of PHP array according to parent keys
I need to flatten an array selectively in PHP, but do it selectively. If the key matches the pattern, then all ancillary items below that key should be included in flat output.
SO If I had a music directory:
=> array of albums => each of which is an array of song titles
Then I could search for a string and get a flat array in the response. So if I were looking for "sun" then I would get the entire catalog for any artist with "sun" on their behalf, plus albums for other artists where "sun" was in the album title.
Hope this makes sense.
Anyone have any thoughts?
a source to share
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 to get: ["Lovely Day", "Use Me", "Ain't No Sunshine", "Piano Man"]
. Here's one way to 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 also assume that you have a good reason not to use a database for this.
a source to share
$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 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;
}
a source to share
To compile NickF to work, assuming your data is similar to his, I would 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 match is found, will explicitly return null instead of an empty array; when multiple matches are found, they will be grouped by their artist. I find a direct purpose $output[$artist] = $songs
to provide more predictable results than array_merge in my own experience. (This also saves the artist to output this data.)
As NickF said, I would assume you have every reason not to do this with a database? The SQL for this would be very simple, for example
SELECT artist, song FROM songs WHERE artist LIKE '%Bill%' GROUP BY artist;
a source to share
You can use preg_grep to search, don't forget to clear your input, however:
$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));
}
a source to share