49

I have two lists of objects; List<X> and List<Y>. X and Y are ojects that look like:

public class X {
    String a;
    String b;
    String v;
    String w;
    String m;
    String n;
}

public class Y {
    String a;
    String b;
    List<A> aList;
}
public class A {
    String v;
    String w;
    List<B> bList;
}
public class B {
    String m;
    String n;
}

How transform List<X> into List<Y> based on a rule:
Some fields' values must be equal.
For example:
In List<Y>, for one object Y, field a's value must equal.
In Y's field List<A>, for one object A, field w's value must equal.
In A's field List<B>, for one object B, field m's value must equal and so on.

Guava has this method, Lists#transform, but I don't know how to transform.

Or any other way?

Andrejs
  • 10,803
  • 4
  • 43
  • 48
zhm
  • 491
  • 1
  • 4
  • 3

6 Answers6

77
public static <F,T> List<T> transform(List<F> fromList,
                                      Function<? super F,? extends T> function

You might want to read up the API docs for Lists.transform() and Function, but basically the caller of the transform provides a Function object that converts an F to a T.

For example if you have a List<Integer> intList and you want to create a List<String> such that each element of the latter contains the english representation of that number (1 becomes "one" etc) and you have a access to a class such as IntToEnglish then

Function<Integer, String> intToEnglish = 
    new Function<Integer,String>() { 
        public String apply(Integer i) { return new IntToEnglish().english_number(i); }
    };

List<String> wordsList = Lists.transform(intList, intToEnglish);

Does that conversion.

You can apply the same pattern to transform your List<X> to List<Y>

luochenhuan
  • 1,057
  • 11
  • 17
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • Not sure if solves the issue but very impressive – Java Ka Baby Sep 12 '11 at 06:34
  • Which api doc are you referring to? – Java Ka Baby Sep 12 '11 at 06:36
  • @Java Ka Baby I mean the docs at http://code.google.com/p/guava-libraries. Google collections API is awesome. Jon Skeet also referred it in your recent question. – Miserable Variable Sep 12 '11 at 07:44
  • Ok thanks Guava seems popular these days have never used it directly will read up :) cheers – Java Ka Baby Sep 12 '11 at 09:48
  • 6
    Here's an interesting gotcha to be aware of: transform returns a *view* of the original list, which is *still* linked to the original list, and not a separate new list. I.e. if you remove an element from the list returned from transform, it will also remove the element from the original list. Just caught me out, so thought I'd share :) – stephendnicholas Sep 06 '16 at 15:22
  • 3
    BE AWARE - Lists.transform() is LAZY! From Guava JavaDoc: Note: serializing the returned list is implemented by serializing fromList, its contents, and function -- not by serializing the transformed values. This can lead to surprising behavior, so serializing the returned list is not recommended. Instead, copy the list using ImmutableList.copyOf(Collection) (for example), then serialize the copy. Other methods similar to this do not implement serialization at all for this reason. – vellotis Mar 21 '18 at 22:56
  • 1
    @vellotis and stephendnicholas, your comments must be included into this answer in UPPERCASE. Really, this is not obvious behavior at all. – Varvara Kalinina Jan 29 '19 at 19:04
  • This was very useful in my scenario to transform role Entity into role DTO. – Chamod Pathirana Jul 14 '19 at 19:51
  • As others mentioned - be aware of Lists.transform! Here https://stackoverflow.com/a/63754218/1694265 I pasted a snippet showing how it may surprise you. – Bunarro Sep 06 '20 at 07:40
17

With java lambda:

public static <K,V,Q extends K> List<V> transform( final List<Q> input, final java.util.function.Function<K,V> tfunc ) {
    if( null == input ) {
        return null;
    }
    return input.stream().map(tfunc).collect( Collectors.toList() );
}

You just need to implement: java.util.function.Function

biliboc
  • 737
  • 1
  • 10
  • 25
7

How about this?

import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

public class GuavaTransform {
    public static void main(String[] args) {
        List<X> xList = new ArrayList<X>();
        xList.add(new X("a", "b", "v", "w", "m", "n"));
        xList.add(new X("a1", "b1", "v1", "w1", "m1", "n1"));
        for(X elem: xList) {
            System.out.println("An instance of X:"+ elem);
        }
        System.out.println();
        List<Y> yList = Lists.transform(xList, new TransformXY());
        for(Y elem: yList) {
            System.out.println("The corresponding instance of Y: \n"+elem);
        }
    }
}

class TransformXY implements Function<X, Y> {

    @Override
    public Y apply(X x) {
        List<B> bList = new ArrayList<B>();
        bList.add(new B(x.m, x.n));
        List<A> aList = new ArrayList<A>();
        aList.add(new A(x.v, x.w, bList));
        return new Y(x.a, x.b, aList);
    }
}

class X {
    String a;
    String b;
    String v;
    String w;
    String m;
    String n;
    X(String a, String b, String v, String w, String m, String n) {
        super();
        this.a = a;
        this.b = b;
        this.v = v;
        this.w = w;
        this.m = m;
        this.n = n;
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        sb.append(a+",");
        sb.append(b+",");
        sb.append(v+",");
        sb.append(w+",");
        sb.append(m+",");
        sb.append(n);
        sb.append(")");
        return sb.toString();
    }
}
class Y {
    String a;
    String b;
    List<A> aList;
    Y(String a, String b, List<A> aList) {
        super();
        this.a = a;
        this.b = b;
        this.aList = aList;
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(a+"\n");
        sb.append(b+"\n");
        for(A elem: aList) {
            sb.append(elem+"\n");
        }
        return sb.toString();
    } 
}
class A {
    String v;
    String w;
    List<B> bList;
    A(String v, String w, List<B> bList) {
        super();
        this.v = v;
        this.w = w;
        this.bList = bList;
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("--------"+v+"\n");
        sb.append("--------"+w+"\n");
        for(B elem: bList) {
            sb.append(elem+"\n");
        }
        return sb.toString();
    }

}
class B {
    String m;
    String n;
    B(String m, String n) {
        super();
        this.m = m;
        this.n = n;
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("----------------"+m+"\n");
        sb.append("----------------"+n+"\n");
        return sb.toString();
    }
}

Console output:

An instance of X:(a,b,v,w,m,n)
An instance of X:(a1,b1,v1,w1,m1,n1)

The corresponding instance of Y: 
a
b
--------v
--------w
----------------m
----------------n



The corresponding instance of Y: 
a1
b1
--------v1
--------w1
----------------m1
----------------n1
blackcompe
  • 3,180
  • 16
  • 27
5

Same as @Isaace but with the lambda syntax (got it from this example):

List<X> xList = new ArrayList<>();
List<Y> yList = xList
        .stream()
        .map(n -> someTransformFunc(n))
        .collect(Collectors.toList());
bartaelterman
  • 795
  • 10
  • 26
4

Java 8 style, IntelliJ IDEA‎ helped me out:

List<X> xList = new ArrayList<>();
List<Y> yList = xList
        .stream()
        .map(X::getY)
        .collect(Collectors.toList());
Isaace
  • 131
  • 6
0

assume have two object can interconversion, Coach and EntityBase

1.declare generic method

   public static <TSourse, TResult> void ToList(List<TSourse> list, List<TResult> results) {
    if (list.size() > 0) {
        for (TSourse obj : list) {
            TResult tResult = (TResult) obj;
            if (tResult == null) {
                throw new AppException("error....");
            }
            results.add(tResult);
        }
    }
}

2.call this method

  List<EntityBase> entityBaseList = new ArrayList<>();
    Coach coach = new Coach();
    coach.setId("123");
    entityBaseList.add(coach);

    List<Coach> coachList = new ArrayList<>();
    ToList(entityBaseList, coachList);
    //will complete List<AObj> to another List<BObj>
anuo
  • 143
  • 2
  • 6