NotionCommotion Posted May 9, 2018 Share Posted May 9, 2018 I need to provide a list of time zones which starts with a given string in id/name pairs, and came up with the following solution. public function timezones($param) { $timezone_identifiers = \DateTimeZone::listIdentifiers(); $timezone_identifiers_selected = []; array_walk($timezone_identifiers, function($name, $id) use (&$timezone_identifiers_selected, $param) { if($this->startsWith($name, $param['term'])) $timezone_identifiers_selected[] = ['id'=>$id, 'name'=>$name]; }); return [$timezone_identifiers_selected,200]; } private function startsWith($haystack, $needle) { return $needle === "" || stripos($haystack, $needle, -strlen($haystack)) !== false; } Before using array_walk, I used array_filter to come up with the list, but not transform the sequence array to an associated array with id and name elements. While I am good with the array_walk solution, I would like to know whether this is possible with any single PHP commands. Kind of like array_columns but in reverse. Thanks $timezone_identifiers_selected = array_filter($timezone_identifiers, function($val) use($param) { return $this->startsWith($val, $param['term']); }); Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted May 9, 2018 Author Share Posted May 9, 2018 In hindsight, I won't be using the DateTimeZone::listIdentifiers id so don't need to make the id/value pairs. Still, however, interested whether it is possible to perform the array transformation. Thanks Quote Link to comment Share on other sites More sharing options...
requinix Posted May 9, 2018 Share Posted May 9, 2018 So, like, you want all timezones that start with "America/" or "Asia/" or something? But why do you want the array key? The array is just a normal indexed array. The key isn't useful. I don't see a way to get the result with just one or two built-in functions, but you can do it like public function timezones($param) { return [iterator_to_array((function($ids, $term, $termlen) { foreach ($ids as $id => $name) { if (strncasecmp($name, $term, $termlen) == 0) { yield ['id' => $id, 'name' => $name]; } } })(\DateTimeZone::listIdentifiers(), $param['term'], strlen($param['term']))), 200]; }but that's silly. Your solution is fine, although I don't care for startsWith being its own method (plus strncasecmp is better for this than stripos). Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted May 9, 2018 Author Share Posted May 9, 2018 Thanks requinix, See my previous "In hindsight..." indicating that I don't need the id. Typically, all my ajax calls use surrogates and originally I wanted to keep consistent, but came to the same conclusion that the key isn't useful. And I was also on the fence about startsWith being its own method. Why is strncasecmp better for this than stripos? Quote Link to comment Share on other sites More sharing options...
requinix Posted May 9, 2018 Share Posted May 9, 2018 Right, saw the reply, promptly forgot about it. str(n)(case)cmp compares characters in two strings starting at the beginning. If any character doesn't match then the function stops. If it reaches the end of a string, or the length limit for the 'n' version, then the function stops. str(i)pos searches for whether one string contains another substring. It starts at one point, checks, and if it doesn't match then advances a character and checks again. And repeats until it finds the substring or reaches the end. In your case you only care if the substring is at the beginning. If it isn't then fail. strncasecmp will do that. stripos will advance to the second character and continue searching, which is wasteful because if it does find the substring you still don't care. It will also return a false positive because you only care if it returns !==false - it should be ===0 instead. stripos("America/New_York", "York", -16) === 12 Quote Link to comment Share on other sites More sharing options...
Psycho Posted May 9, 2018 Share Posted May 9, 2018 While I understand what you originally wanted is no longer needed and you are now just asking for curiosity - I would suggest trying not to "push" a bunch of logic into a single line. Makes it much more difficult to read the code. I would use array_filter() to remove the unwanted entries - then create a new array in the new format you want. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.