Reputation: 809
In Haskell there is a function called map
, which takes a List of Type A
and a function f
, mapping values of type A
to values of type B
. It returns a list of type B
, such that each element of the result list originates from a call of f
to a value in the input list.
For example, given
m = ['a', 'b', 'c']
,f = {'a' -> 1, 'b' -> 2, 'c' -> 3}
,map(m, f) = [1, 2, 3]
.Is there a library, usable with Java 7, that offers something like the map
function? I already viewed apache CollectionUtils and found things like forAllDo and transform, but they don't allow retuning a collection of a completely different type. Googling for other libraries failed for the same reason.
To be clear: I know how to solve the problem by myself, but I strongly feel that there must already exist a good library that performs this task more generally.
Bonus question: Is there some equivalent to Haskell functors (i.e. move from collections to iterables) usable in Java 7? Further explanation: Is there a map function which takes an Iterable<A>
instead of Collection<A>
and returns an Iterable<B>
instead of Collection<B>
(provided by a fitting function f
)?
Upvotes: 9
Views: 1212
Reputation: 60094
You need use Stream APi from Java 8. Using official API you cann't using Stream APi in Java 7, but using:
you can. More info see this post and documentation retrolambda, totallylazy, gradle-retrolambda or Lightweight-Stream-API. But if you can using Java 8, it's much more easy than using non official API.
Or you can use
to use functional programming in Java 7, but Stream API more offical and general.
Upvotes: 2
Reputation: 23329
Functional transformations were added to Java 8 and they are not available for Java 7. For example, a map function that transforms a String to an integer looks like this Java 8
List<String> list = Arrays.asList("1","2","3");
List<Integer> nums = list.stream().map(Integer::parseInt).collect(Collectors.toList());
Unlike Haskell, Java collections are strict, however Streams
( Java 8) are lifted
( ~ lazy).
There are libraries that support higher order functions
for Java 7
like Guava
. Guava has a transform
function that transforms T -> U, for ex:
Collection<Integer> ints = Collections2.transform(list, new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
});
But as you can tell ,due to the lack of lambda expressions in Java 7, it doesn't look concise
Upvotes: 4
Reputation: 65793
You can write yourself an Iterator
that takes a map
object that does the transformation.
static class Transformer<F, T> implements Iterator<T> {
final Iterator<F> source;
final Map<F, T> map;
public Transformer(Iterator<F> source, Map<F, T> map) {
this.source = source;
this.map = map;
}
@Override
public boolean hasNext() {
return source.hasNext();
}
@Override
public T next() {
return map.map(source.next());
}
public interface Map<F, T> {
public T map(F f);
}
}
private static final String[] numbers = {"Zero", "One", "Two", "Three", "Four", "Five"};
public void test() {
List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
Transformer t = new Transformer<>(ints.iterator(), new Transformer.Map<Integer, String>() {
@Override
public String map(Integer f) {
return numbers[f];
}
});
while (t.hasNext()) {
System.out.println(t.next());
}
}
Upvotes: 3
Reputation: 5185
You are asking for Java 7 (with Java 8 it's easier):
You can use Guava and there specifically FluentIterable
final List<String> strings = Arrays.asList("a", "b", "c");
final List<Integer> integers = FluentIterable
.from(strings)
.transform(new Function<String, Integer>() {
@Nullable
@Override
public Integer apply(@Nullable String input) {
return input.equals("a") ? 1 : input.equals("b") ? 2 : input.equals("c") ? 3 : -1;
}
})
.toList();
Bonus question: A collection is an iterable :-)
Upvotes: 12
Reputation: 13262
I don't know such a library, but what is wrong using the plain java, like:
List<String> m;
Map<Key,String> map = new HashMap<Key,String>();
int c=1;
for (String i : m) map.put(i,c++);
Upvotes: 1