5

In Scala, there is a method that looks something like this.

List[(A, B)] = List.fill(n)(doSomething(arg))

My question is if there is any way to do this in Java, or if it would have to be done through a series of lengthy fors and what have you.

Java does have Collections.fill but it doesn't seem to do what I want it to do.

Scala implementation is as follows:

def buyCoffee(cc: CreditCard): (Coffee, Charge) =
{
    val cup = new Coffee()
    (cup, Charge(cc, cup.price))
}
def buyCoffees(cc: CreditCard, n: Int): (List[Coffee], Charge) =
{
    val p: List[(Coffee, Charge)] = List.fill(n)(buyCoffee(cc))
}

This does not seem achievable in Java to me, or not from what I know of Java or what I have been able to find in the documentation thus far.

This Scala code can be found on Page 7 of Functional Programming in Scala by Paul Chiusana and Rúnar Bjarnason.

m482
  • 47
  • 5
  • what is the implementation of the `doSomehing()` ? – Wael Sakhri Jan 29 '16 at 13:13
  • `Collections.fill` will replace all items inside a collections with the specified object. You need to do something special, like only fill if a conditions is met? – kunpapa Jan 29 '16 at 13:14
  • I've updated with the Scala implementation of the relevant section. – m482 Jan 29 '16 at 13:18
  • @kunpapa Yeah, as long as it's from Java 7 or before. Java 8 is not applicable here, unfortunately. We could use something like the example below if Java 8 were usable. I'd like to see what anyone could come up with or suggestions on what to use for Java7 implementation of this. – m482 Jan 29 '16 at 13:24

5 Answers5

6

There is an equivalent with Java 8 :

  • Use a Stream to generate a sequence
  • For each value of the sequence, map it using whichever method you want
  • Collect the result

Example :

List<Result> collect = IntStream.range(0, 5)
                      .mapToObj(i -> doSomething(i))
                      .collect(Collectors.toList());

public Result doSomething(Integer i) {
  return ...;
}
Arnaud Denoyelle
  • 29,980
  • 16
  • 92
  • 148
1

There is a JEP for creating small collections or the issue is easier to read.

It shows a couple of idioms, one of which uses an initializer. A Java 8 version of fill:

import java.util.*;
import java.util.function.*;

public class j {
  public static <T> List<T> fill(int n, Function<Integer, T> f) {
    return Collections.unmodifiableList(new ArrayList<T>(n) {{
      for (int i = 0; i < n; i++) add(f.apply(i));
    }});
  }
  public static void main(String[] args) {
    List<Integer> values = fill(10, i -> 2 * i);
    for (int x : values) System.out.println(x);
  }
}

I haven't looked for a JEP for other conveniences, but it's clear that these API are on their minds.

som-snytt
  • 39,429
  • 2
  • 47
  • 129
0

Simple for format:

ArrayList<Coffee> array = new ArrayList<Coffee>();
// array.add("Coffe Expresso") ...
CreditCard cc = new CreditCard("1234 4321 1234 4321");
for(Coffee obj : array){
   obj = new Coffee("Coffee - no sugar");
   buyCoffee(obj, cc);
}

public void buyCoffee(Coffee coffee, CreditCard cc){
    //...
}
kunpapa
  • 367
  • 1
  • 9
0

I am not sure, what it is you are trying to "achieve" in java, that seems "unachievable" to you.

List list = new ArrayList();
for(int i = 0; i < n; i++) list.add(buyCoffee(cc));

is hardly much "lengthier" than what you had in scala. What is the problem you see with it?

Java is not a functional language, and there is no point in trying to use it as if it was: if you want functional, just use scala.

Even the solutions people suggested for java8, do not look pretty (longer, than this one), are harder to read, and have subtle problems (such as, byCoffee cannot throw exceptions, a lot of intermediate collections are allocated etc.)

If you are writing java code, it is better to use idiomatic java, unless there is a rational justification against it.

Dima
  • 39,570
  • 6
  • 44
  • 70
0

This is surely the roundabout way of answering the question, and is certainly not a replacement for "fill" or other functional-programming methods. However, it works for this implementation in Java, which is the main issue at this point.

class Cafe
{

Results buyCoffee(CreditCard cc)
{
    Coffee cup = new Coffee();
    List<Results> myList = new ArrayList<Results>();

    myList.add(0, new Results(cup, new Charge(cc, cup.price)));
    return myList.get(0);
}


Map<List<Coffee>, Charge> buyCoffees(CreditCard cc, int n)
{
    List<Results> purchases = new ArrayList<Results>(n);
    for(int a = 0; a < n; a++)
    {
        Results r = new Results();
        r = buyCoffee(cc);
        purchases.add(r);
    }

    List<Coffee> coffeeList = new ArrayList<Coffee>(n);
    List<Charge> chargeList = new ArrayList<Charge>(n);

    for(int b = 0; b < n; b++)
    {
        Coffee c = purchases.get(b).ThisCoffee;
        Charge charge = purchases.get(b).ThisCharge;
        coffeeList.add(c);
        chargeList.add(charge);
    }

    Charge fc = new Charge();
    Double[] ChargeAmountArray = new Double[n];

    for(int d = 0; d < n; d++)
    {
        Double x = chargeList.get(d).amount;
        ChargeAmountArray[d] = x;
    }

    double sum = 0;

    for(Double d: ChargeAmountArray)
    {
        sum += d;           // 50.0@n=5, 100.0@n=10
    }

    Charge finalCharge = new Charge(cc, sum);

    Map<List<Coffee>, Charge> map;
    map = new HashMap<List<Coffee>, Charge>();
    map.put(coffeeList, finalCharge);
    return map;
}
}
m482
  • 47
  • 5