user3389669
user3389669

Reputation: 809

Equivalent to map (from haskell) in Java 7

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

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

Answers (5)

Slava Vedenin
Slava Vedenin

Reputation: 60094

You need use Stream APi from Java 8. Using official API you cann't using Stream APi in Java 7, but using:

  1. retrolambda,
  2. totallylazy,
  3. gradle-retrolambda, or
  4. Lightweight-Stream-API

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

  1. FunctionalExplained Guava
  2. Functional Java lib

to use functional programming in Java 7, but Stream API more offical and general.

Upvotes: 2

Sleiman Jneidi
Sleiman Jneidi

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

OldCurmudgeon
OldCurmudgeon

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

spa
spa

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

dan
dan

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

Related Questions