Skip to content

Instantly share code, notes, and snippets.

@wilmoore
Last active October 12, 2015 03:58
Show Gist options
  • Save wilmoore/3967818 to your computer and use it in GitHub Desktop.
Save wilmoore/3967818 to your computer and use it in GitHub Desktop.
Filter and Sort (least concise and enjoyable to write from the top, to the most concise and enjoyable at the bottom)
<?php
$fields = array('firstName', 'middleName', 'lastName', 'suffix');
$names[] = array('firstName' => 'Diane ', 'middleName' => 'Tanya ', 'lastName' => ' Douglas', 'suffix' => '');
$names[] = array('firstName' => 'Jon ', 'middleName' => '', 'lastName' => ' Watson', 'suffix' => '');
$names[] = array('firstName' => ' Michelle ', 'middleName' => '', 'lastName' => ' Ajuria', 'suffix' => '');
$names[] = array('firstName' => 'Elliot ', 'middleName' => '', 'lastName' => 'Gray ', 'suffix' => 'II');
$names[] = array('firstName' => ' Jason ', 'middleName' => '', 'lastName' => 'Doran', 'suffix' => '');
// drop superfluous spaces and empty name parts (i.e. if there is no middle name, get rid of it)
$names = array_map(function($name) {
return array_map(function($part){ return trim($part); }, $name);
}, $names);
// drop records with last names starting with 'W'
$names = array_filter($names, function($name) {
return !preg_match('/^[w]/iu', $name['lastName']);
});
// sort descending by last name (names closer to Z first)
usort($names, function($a, $b){ return strcmp($b['lastName'], $a['lastName']); });
// build an array where each value corresponds to a person's full name (i.e. Diane Tanya Douglas)
$names = array_map(function($name) use($fields) {
return array_reduce($fields, function($parts, $field) use($name) {
if (!empty($name[$field])) $parts[] = $name[$field]; return $parts;
}, array());
}, $names);
// print names one per line (use portable line break -- i.e. line break of the current OS)
foreach ($names as $name) { echo join(' ', $name), PHP_EOL; }
var fields = ['firstName', 'middleName', 'lastName', 'suffix'],
names = [
{'firstName': 'Diane ', 'middleName': 'Tanya ', 'lastName': ' Douglas', 'suffix': '' },
{'firstName': 'Jon ', 'middleName': '', 'lastName': ' Watson', 'suffix': '' },
{'firstName': ' Michelle ', 'middleName': '', 'lastName': ' Ajuria', 'suffix': '' },
{'firstName': 'Elliot ', 'middleName': '', 'lastName': 'Gray ', 'suffix': 'II' },
{'firstName': ' Jason ', 'middleName': '', 'lastName': 'Doran', 'suffix': '' }];
// trim superfluous white-space
names.forEach(function(name){
Object.keys(name).forEach(function(field){ name[field] = name[field].trim() })
})
// drop records with last names starting with 'W' and sort
names = names.filter(function(name){ return !/^w/i.test(name.lastName) })
.sort(function(a, b){ return (a.lastName === b.lastName) ? 0 : (a.lastName > b.lastName) ? -1 : 1;})
// print full names one per line ignoring empty name parts (i.e. if middle name is empty, get rid of it)
names.forEach(function(name){
name = fields.reduce(function(result, field){ name[field] && result.push(name[field]); return result; }, [])
console.log(name.join(' '))
})
import scala.collection.mutable.Map
val fields = List("firstName", "middleName", "lastName", "suffix")
var names = List(
Map("firstName" -> "Diane" , "middleName" -> "Tanya " , "lastName" -> " Douglas", "suffix" -> "" ),
Map("middleName" -> "" , "firstName" -> "Jon " , "lastName" -> " Watson" , "suffix" -> "" ),
Map("firstName" -> " Michelle ", "lastName" -> " Ajuria", "middleName" -> "" , "suffix" -> "" ),
Map("firstName" -> "Elliot " , "suffix" -> "III" , "middleName" -> "" , "lastName" -> "Gray "),
Map("firstName" -> " Jason " , "middleName" -> "" , "lastName" -> "Doran" , "suffix" -> "" ))
// trim superfluous spaces
names foreach { name => name foreach {case (key, value) => name(key) = value.trim() } }
// drop records where last name starts with 'W'
names = names filterNot { _("lastName").startsWith("W")}
// sort descending by last name
names = names sortWith { (e1, e2) => (e1("lastName") compareTo e2("lastName")) < 0 } reverse
// print full names one per line ignoring empty name parts (i.e. if middle name is empty, get rid of it)
names foreach { name =>
var record:List[String] = Nil
for(field <- fields reverse) if (name(field).length > 0) record = name(field) :: record
println(record.mkString(" "))
}
fields = [:firstName, :middleName, :lastName, :suffix]
names = [
{firstName: 'Diane' , middleName: 'Tanya ' , lastName: ' Douglas', suffix: '' },
{middleName: '' , firstName: 'Jon ' , lastName: ' Watson' , suffix: '' },
{firstName: ' Michelle ', lastName: ' Ajuria', middleName: '' , suffix: '' },
{firstName: 'Elliot ' , suffix: 'III' , middleName: '' , lastName: 'Gray '},
{firstName: ' Jason ' , middleName: '' , lastName: 'Doran' , suffix: '' }]
# trim superfluous spaces
names.each {|name| name.each {|key, val| name[key].strip!}}
# drop records where last name starts with 'W'
names.reject! {|name| name[:lastName].match(/^w/i)}
# sort descending by last name
names.sort_by! {|name| name[:lastName]}.reverse!
# print full names one per line ignoring empty name parts (i.e. if middle name is empty, get rid of it)
names.each do |name|
puts fields.inject([]) {|parts, field| parts << name[field] unless name[field].empty?; parts}.join ' '
end
@wilmoore
Copy link
Author

A few note-worthy items:

  • The JavaScript version uses a self-invoked function expression / closure for scoping...this adds two lines so this could have been done in 24 to match the Scala example.
  • The Scala example, while impressively concise, still suffers from a bunch of extra keywords. This is likely my newb status with Scala. There is likely a more idiomatic and concise way to write this.
  • The Ruby example, on line 20; I would not have done this with any other language as it would have been a nightmare to read, yet with Ruby, it reads just fine.
  • To be fair to JavaScript, if I were only targeting NodeJS, I'd drop the self-invoked function expression and I'd create modules to encapsulate the sort (re-usable comparator function with a descriptive name) and the filter lines (change filter to Ruby-like 'reject' function) so they read better.

@wilmoore
Copy link
Author

  • Oh, and also, I'd import a 'trim' function for the JavaScript example if targeting NodeJS.

@wilmoore
Copy link
Author

Output

Elliot Gray III
Diane Tanya Douglas
Jason Doran
Michelle Ajuria

@wilmoore
Copy link
Author

Updated JavaScript example to remove the self-invoked function expression.

@wilmoore
Copy link
Author

More observations

  • "_" is an awesome language feature. Every language should have this.
  • If JavaScript had a better standard library, it would be a beast of a language (it already is, so imagine if it had native startsWith, reject, sortBy).
  • ES6 has startsWith so you can and should either shim it in or add it to a small string lib.

@wilmoore
Copy link
Author

Even more

  • I had forgotten that ES5 had .trim -- that puts JavaScript in a good place, very close to Ruby in my opinion.
  • Even though Ruby wins slightly in LOC, that misses the point. The Ruby code is miles more readable than every other option, even fairly concise and idiomatic JavaScript.
  • At the end of the day, PHP (even with 5.4 syntax), is no-where close to the expressiveness of JavaScript, let alone Ruby.

@wilmoore
Copy link
Author

Rant on PHP for a minute

  • While PHP actually has a respectable standard library, it is horrible regarding API consistency.
  • Even with a vastly better standard library than JavaScript, PHP is still horrendous to read compared to pretty much everything else. I mean, I didn't even post the Python, CoffeeScript, and Groovy examples. I just felt like that would have crushed all life out of the PHP example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment