3

I have an array with Type B[]. I have a constructor A(B b).

I want to create an array with Type A[] using them.

I can use the for statement to do that, but I want to know whether there is a more convinient(shorter) way to do this. (Language syntax, static method, or whatever)

public class A {
    public A(B b) {
        A.a = B.a;
        A.b = B.b * B.c;
        ...
    }
}

public class B {
    ...
}

public class C {
    public static B[] getBs() {
        B[] bs;
        ...
        return bs;
    }
}

void process() {
    // From here
    B[] bs = C.getBs();
    A[] as = new A[bs.length];
    for (int i=0; i<bs.length; i++) {
        as[i] = new A(bs[i]);
    }
    // To here
}
Naetmul
  • 14,544
  • 8
  • 57
  • 81
  • 2
    Your logic that explains how the two arrays are related is quite sketchy to me. Maybe it's me, but if you don't get good answers, consider clarifying this a bit. e.g., what does this mean: `A.b = B.b * B.c;`? Why are you using the type, B, in A's constructor body and not the parameter, b? What will `A.c` be? How is A.b an array item? And finally and most importantly, please post *real* code, not *sort-of maybe* code which appears to be what you're posting here. – Hovercraft Full Of Eels Aug 09 '13 at 03:34
  • Yes please try to post real code. We may be able to help more if we can see exactly what you are trying to do instead of seeing what you kinda, may, possibly, be thinking about. – Bmize729 Aug 09 '13 at 05:39

3 Answers3

4

As of the current1 state of the language2, about the best that you can do is something like this3:

interface Transformer<A, B> {
    B transform(A a);
}

class ArrayUtils {
    @SuppressWarnings("unchecked")
    public static <A, B> B[] transformArray(
        Class<B> clazz,
        A[] a,
        Transformer<A, B> transformer
    ) {
        B[] b = (B[])Array.newInstance(clazz, a.length);
        for(int i = 0; i < a.length; i++) {
            b[i] = transformer.transform(a[i]);
        }
        return b;
    }
}

Usage:

Foo[] foos = // some Foo array
Bar[] bars = 
    ArrayUtils.transformArray(
        Bar.class,
        foos,
        new Transformer<Foo, Bar>() {
            public Bar transform(Foo foo) { return new Bar(foo); } 
        }
    );

This assumes:

class Foo { }
class Bar { public Bar(Foo foo) { } }

1: There are features coming in 2014(?) that will make it easier.

2: Remember boys and girls, the next time you design a type system of your own from scratch, remember to add generics early, rather than adding them on later.

3: Just hacked this together. Feel free to help fix any bugs. :-)

Community
  • 1
  • 1
jason
  • 236,483
  • 35
  • 423
  • 525
  • 1
    Those features are outlined in [my answer](http://stackoverflow.com/a/18139765/758280) ;) – Jeffrey Aug 09 '13 at 03:57
  • @Jeffrey: Awesome. :-) – jason Aug 09 '13 at 03:58
  • IMHO, it's overkill, too much boilerplate. I would go with a custom loop, which is much more light, clean, reliable and IDE friendly. Patterns should be used to make a design more obvious, not less. – fernacolo Aug 09 '13 at 04:27
3

Not yet. In Java 8, we will have access to more functional programming features thanks to Project Lamda, such as map functions.

In Java 8, the following would be valid:

B[] bs = C.getBs();
List<A> aList = Stream.of(bs).map(b -> new A(b)).collect(Collectors.toList());
A[] as = aList.toArray(new A[aList.size()]);

This uses a lamda expression, and several other new features1,2.

While this may not be much "shorter," Stream provides parallelization by default, so if you changed Stream.of(bs) to Stream.of(bs).parallel() in the above example, it would perform much better with large arrays on a multi-core machine.

/edit
You could also use a method reference instead of the lambda expression:

map(A::new) instead of map(b -> new A(b))

Jeffrey
  • 44,417
  • 8
  • 90
  • 141
  • @fernacolo To a certain extent it is, but it is still far less scalable. – Jeffrey Aug 09 '13 at 04:30
  • Agree about scalability. However, to be worth of tasks of creating and synchronizing, either the number of items should be massive (something like 10k or more), or the creation of each item should be computation intensive. Threads always introduce indeterminism (suppose B's creation employs a cache...). – fernacolo Aug 09 '13 at 04:35
1

As of Java 7, you already use the shortest possible loop:

for (int i = 0; i < bs.length; ++i) {
    as[i] = new A(bs[i]);
}

However, if you use collections instead of arrays, you can use "for each":

for (B b: bs) {
    as.add(new A(b));
}

Collections will also give you other flexibilities and shortcuts.

fernacolo
  • 7,012
  • 5
  • 40
  • 61