This document provides code examples in Java, Groovy, Scala, and Jython for solving the anagram problem of finding all permutations of words that can be formed from letters in a given input. The Java code is presented first, followed by simplified versions using Groovy, Scala, and Jython that take advantage of features in those languages like closures, functional programming, and dynamic typing. The examples demonstrate building a multimap to group words by their alphagrams, filtering to find groups above a minimum size, sorting the results, and printing the output.
4. Interview With Josh Bloch
Can you give us an example of code that you are most
proud of creating and explain why?
The Collections framework. It's far from perfect, but it's
proven itself maintainable and pleasant over the years.
Doug Lea built many parts of java.util.concurrent atop it.
And I still get letters from programmers telling me how
much more pleasant it makes their jobs. It lets you write
stuff like this little program, which computes all the
anagrams in the file on standard input.
From “2008 JavaOne Conference - Rock Star Joshua Bloch”
http://java.sun.com/javaone/sf/2008/articles/rockstar_joshuabloch.jsp
4
6. Java Example
import java.util.*;
public class Anagram {
public static void main(String[] args)
{
int minGroupSize = Integer.parseInt(args[0]);
// Read words from input and put into simulated multimap
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
// Print all permutation groups above size threshold
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
System.out.println(group.size() + ": " + group);
}
private static String alphagram(String s)
{
char[] chars = s.toCharArray();
Arrays.sort(chars);
return String.valueOf(chars);
}
} From “2008 JavaOne Conference - Rock Star Joshua Bloch”
http://java.sun.com/javaone/sf/2008/articles/rockstar_joshuabloch.jsp 6
7. Java Example With Deluxe Features
import java.util.*;
public class Anagram {
public static void main(String[] args) {
int minGroupSize = Integer.parseInt(args[0]);
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram); Multimap
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize) Filter
winners.add(group);
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
return o2.size()-o1.size(); Sort
}
});
for (List<String> winner: winners)
System.out.println(winner.size() + ": " + winner);
}
Print
private static String alphagram(String s) {
char[] chars = s.toCharArray();
Arrays.sort(chars); Alphagram
return String.valueOf(chars);
}
} Additional code from “The Java™ Tutorial > Collections”
http://download.oracle.com/javase/tutorial/collections/algorithms/index.html 7
9. What is Groovy?
• Definition
– A lightweight, low-ceremony, dynamic, object-oriented language
– Open sourced under Apache License, version 2.0
– “marvelous, wonderful, excellent, hip, trendy.” (Merriam-
Webster)
• Like Java
– Follows Java semantics
– Seamlessly integrates with Java
– Compiles into Java bytecode
– Extends the Java API and libraries
– Groovy scripts can be injected into Java
• Not like Java
– Dynamic Language
– Closures
– Properties
– Native syntax for lists, maps, and regular expressions
9
11. Groovy: Building Multimap
Java
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
Groovy
anagrams = (new Scanner(System.in)).toList().groupBy {it.alphagram()}
11
12. Groovy: Filtering, Sorting, Printing
Java
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
winners.add(group);
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
return o2.size()-o1.size();
}
});
for (List<String> winner: winners)
System.out.println(winner.size() + ": " + winner);
Groovy
winners = anagrams.values().findAll { it.size > minWordCount }
winners = winners.sort { -it.size }
winners.each { println "${it.size} : $it" }
12
13. Groovy: Putting It All Together
String.metaClass.alphagram = {
return delegate.toList().sort().join()
}
minWordCount = args[0].toInteger();
(new Scanner(System.in)).toList()
.groupBy { it.alphagram() }
.values()
.findAll { it.size > minWordCount }
.sort { -it.size }
.each { println "${it.size} : $it" }
13
14. Java Reminder
import java.util.*;
public class Anagram {
public static void main(String[] args) {
int minGroupSize = Integer.parseInt(args[0]);
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
winners.add(group);
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) { String.metaClass.alphagram = {
return o2.size()-o1.size(); return delegate.toList().sort().join()
} }
});
for (List<String> winner: winners) minWordCount = args[0].toInteger();
System.out.println(winner.size() + ": " + winner);
} (new Scanner(System.in)).toList()
.groupBy { it.alphagram() }
private static String alphagram(String s) { .values()
char[] chars = s.toCharArray(); .findAll { it.size > minWordCount }
Arrays.sort(chars); .sort { -it.size }
return String.valueOf(chars); .each { println "${it.size} : $it" }
}
}
14
16. What is Scala?
• Like Java
– Bytecode looks very similar to javac output
– Familiar object-oriented concepts
– Static types, only better (better type inference, better generics,
implicit parameters)
– Performance equivalent to Java
– Java code can depend on Scala code
• Not like Java
– Functional principles
– Closures
– Everything is an object
– No such thing as static
– Greatly improved type inference and generics
– Traits (mixins)
– Pattern Matching
16
18. Scala: Building Multimap
Java
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
Scala
val map =
new BufferedReader(new InputStreamReader(System.in))
.readLine().split(" ").groupBy( _.sorted)
18
19. Scala: Filtering And Sorting
Java
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
winners.add(group);
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
return o2.size()-o1.size();
}
});
Scala
val winners = map.values.filter(_.size > Integer.parseInt(args(0))).toList
val sorted = winners.sortBy(-_.size)
19
20. Scala: Printing
Java
for (List<String> winner: winners)
System.out.println(winner.size() + ": " + winner);
Scala
for (winner <- sorted.view)
println(winner.size + ": " + winner)
Scala – Another Way
sorted.view.map(list => list.size + ": " + list).foreach(println)
20
24. What is Jython?
• Like Java
– Have access to Java standard libraries and third party libraries
• Not like Java
– Language is Python; latest release conforms to Python 2.5
– Dynamically typed
– Choice of using procedural, object oriented, or functional
programming constructs, or a mixture of the three
– Have access to the Python standard libraries and any pure
Python third party library
• Not like Python
– No access to compiled Python libraries
– Some library features are not available (like fork) due to the
restrictions of the JVM
24
26. Jython: Building Multimap
Java
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
Jython
anagrams = [list(g) for k, g in
itertools.groupby(
sorted(sys.stdin.readline().split(), key =alpha),
alpha)]
26
27. Jython: Filtering
Java
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
winners.add(group);
Jython
winners = (f for f in anagrams if len(f) > int(sys.argv[1]))
List comprehension:
<output> for <variables> in <collection> if <filter>
{<output>|<variables> <collection>, <filter>}
э
27
28. Jython: Sorting
Java
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
return o2.size()-o1.size();
}
});
Jython
winners = sorted(winners, key = lambda t: -len(t))
28
29. Jython: Printing
Java
for (List<String> winner: winners)
System.out.println(winner.size() + ": " + winner);
Jython
for winner in winners:
print '%i: %s '%(len(winner), winner)
29
30. Jython: Complete Example
import itertools
alpha = lambda l : ''.join(sorted(l))
winners = [
f for f in
sorted (
[list(g) for k, g in
itertools.groupby(
sorted(sys.stdin.readline().split(), key = alpha),
alpha)],
key = lambda t: -len(t) )
if(len(f) > int(sys.argv[1]))]
for winner in winners:
print '%i: %s '%(len(winner), winner)
30
31. Java Reminder
import java.util.*;
public class Anagram {
public static void main(String[] args) {
int minGroupSize = Integer.parseInt(args[0]);
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
String word = s.next();
String alphagram = alphagram(word);
List<String> group = anagrams.get(alphagram);
if (group == null)
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
}
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize) import itertools
winners.add(group); alpha = lambda l : ''.join(sorted(l))
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
winners = [
return o2.size()-o1.size(); f for f in
} sorted (
}); [list(g) for k, g in
for (List<String> winner: winners) itertools.groupby(
System.out.println(winner.size() + ": " + winner); sorted(
} sys.stdin.readline().split(), key=alpha),
alpha)],
private static String alphagram(String s) { key = lambda t: -len(t) )
char[] chars = s.toCharArray(); if(len(f) > int(sys.argv[1]))]
Arrays.sort(chars);
return String.valueOf(chars); for winner in winners:
} print '%i: %s '%(len(winner), winner)
}
31
32. Jython: A “Simple” Example
import java.util.*;
def sort_string(buf):
l class Anagram {
public = list(buf)
public static void main(String[] args) {
l.sort()
int minGroupSize = Integer.parseInt(args[0]);
return ''.join(l)
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (Scanner s = new Scanner(System.in); s.hasNext();) {
def get_words():
String word = s.next();
fp = open('dictionary', 'r')
String alphagram = alphagram(word);
words = [ l.strip() for l in fp.readlines() ]
List<String> group = anagrams.get(alphagram);
words.sort() null)
if (group ==
return words
anagrams.put(alphagram, group = new ArrayList<String>());
group.add(word);
def }
get_lists_of_size(list_lists, min_size):
List<List<String>> winners = new ArrayList<List<String>>();
return [ l for l in list_lists if len(l) >= min_size ]
for (List<String> group : anagrams.values())
if (group.size() >= minGroupSize)
def main():
winners.add(group);
all_anagrams = {}
Collections.sort(winners, new Comparator<List<String>>() {
for word int get_words():
public in compare(List<String> o1, List<String> o2) {
key = sort_string(word)
return o2.size()-o1.size(); a
av
if all_anagrams.has_key(key):
e J ge!
}
rit a
}); all_anagrams[key].append(word)
else:
for (List<String> winner: winners)
w u
an lang
System.out.println(winner.size() + ": " + winner);
all_anagrams[key] = [word]
}
u c ny
Yo alphagram(String s)8){
list_lists = all_anagrams.values()
private static String a
in
winners = get_lists_of_size(anagrams,
char[] chars = s.toCharArray();
winners.sort(cmp=lambda x,y: cmp(-len(x), -len(y)))
Arrays.sort(chars);
for winner in winners:
return String.valueOf(chars);
} print "%d : %s" % (len(winner), winner)
}
32
34. What is Clojure?
• Like Java
– Not much, really
– Data structures implement the read-only portion of Collection
– Functions implement Runnable & Callable
• Not like Java
– Dynamic, functional language
– Not object-oriented (!)
– Persistent, immutable data structures
– Lazy sequence abstraction
– Software transactional memory
– Multimethods and ad-hoc hierarchies
– Macros
• Compared to Common Lisp/Scheme
– Persistent, immutable data structures
– First-class Vectors, Sets, and Maps
– Focus on concurrency
– No tail call optimization; explicit calls to recur and trampoline required
34
42. What is JRuby?
• Like Java
– Have access to Java standard libraries and third party
libraries
– Runs in a JVM
• Not like Java
– Language is Ruby; latest release conforms to Ruby 1.8.7
– Dynamically typed
– Can compile to class files
– Have access to the Ruby standard libraries and any pure
Ruby third party library
• Not like Ruby
– No access to Ruby native-C API
– No access to Ruby continuations
42
47. JRuby: Complete Example – Let’s Make It Better
class String
def collation
self.chars.sort.join
end
end
class Symbol
def to_proc
proc { |*args| args[0].send(self, *args[1...args.size]) }
end
end
module Enumerable
def partitioned_with(&transformer)
group_by(&transformer).values
end
def longer_than(size)
self.select {|e| e.length > size}
end
def sorted_by_size
self.sort_by(&:length)
end
end
47
48. JRuby: Better Complete Example
groups = words.partitioned_with(&:collation)
winners = groups.longer_than(4).sorted_by_size
winners.each{|each| puts "#{each.size}: #{each.join(', ')}"}
48
49. Takeaways
• JVM provides a robust, industrial strength, scalable
platform
• You can take advantage of JVM and the rest of the
Java ecosystem without the complexity of Java the
language
• Don’t have to wait for Java to adopt the features
already available in other languages: closures, dynamic
capabilities, rich, humane interfaces
• Not all languages are enterprise ready
– These languages are still worth looking into
• Pragmatic Programmer advice:
Learn a new language every year. When you learn a
new language, you learn a new way to think.
49