如何将List<X>转换为另一个List<Y>?

49

我有两个对象列表:List<X>List<Y>XY 都是长这样的对象:

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;
}
如何基于某个规则将List<X>转换成List<Y>
一些字段的值必须相等。
例如:
List<Y>中,对于一个对象Y,其字段a的值必须相等。
在Y的List<A>字段中,对于一个对象A,其字段w的值必须相等。
在A的List<B>字段中,对于一个对象B,其字段m的值必须相等,以此类推。
Guava有这个方法Lists#transform,但我不知道如何进行转换。
还有其他什么办法吗?

3
  1. 你说“字段a的值必须等于”?等于什么?
  2. 如果这些条件不满足会发生什么?
- NullUserException
1
我认为没有内置函数可以实现这种级别的转换。你只能自己循环和检查。 - Java Ka Baby
“field a的值必须等于”,将List<X>转换为List<Y>,X的字段a必须等于Y的字段a,X的字段w必须等于对象Y中的字段w等等...如果条件无法满足,因为如果a为空,则只需使用空字段a创建一个新的Y。 - zhm
还是不太清楚。在 Y 中有一个 List<A>,这个列表应该有多少个 A 对象?如果超过一个,它们是否都具有相同的值? - NullUserException
好的,让我们更容易理解一些。X是数据库中的一个表,我想将其转换为三个表,这些表之间的关系类似于Y。我使用hibernate。这是主键和外键关系。由于我无法设计表格,因此表A中的某些列可能会在B或Y中更改,因此我希望为此转换提供功能级别,如果有任何更改,它很容易重建和重新分组。 - zhm
6个回答

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

您可能需要阅读 Lists.transform()Function 的API文档,但基本上是调用者提供一个将F转换为TFunction对象来实现转换。

例如,如果您有一个List<Integer> intList,并且您想创建一个List<String>,使得后者的每个元素都包含该数字的英语表示(1变成“one”等),并且您可以访问诸如IntToEnglish之类的类,则可以这样做:

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);

能够实现这种转换。

您可以应用相同的模式将您的 List<X> 转换为 List<Y>


不确定是否解决了问题,但非常令人印象深刻。 - Java Ka Baby
你指的是哪个API文档? - Java Ka Baby
6
这里有一个有趣的陷阱需要注意:transform返回原始列表的视图,仍然与原始列表相连,而不是一个单独的新列表。也就是说,如果你从transform返回的列表中移除一个元素,它也会从原始列表中移除该元素。这个问题曾经让我措手不及,所以我想分享一下 :) - stephendnicholas
3
注意:Lists.transform() 是惰性求值的!根据 Guava JavaDoc 的说明:请注意,将返回的列表序列化是通过从 fromList、其内容和函数进行序列化实现的,而不是通过序列化转换后的值。这可能会导致出乎意料的行为,因此不建议序列化返回的列表。相反,使用 ImmutableList.copyOf(Collection)(例如)复制列表,然后对副本进行序列化。由于这个原因,类似于这样的其他方法根本不实现序列化。 - vellotis
1
@vellotis 和 @stephendnicholas,你们的评论必须用大写字母包含在这个答案中。事实上,这并不是显而易见的行为。 - Varvara Kalinina
显示剩余4条评论

17

使用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() );
}

您只需要实现:java.util.function.Function


这很好。使用Java API而无需安装Guice。 - Rudy

7
这个怎么样?
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();
    }
}

控制台输出:

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

1
+1表示“Guava”,用水果解释是最好的主意。 - mohdajami

5

与 @Isaace 相同,但使用 lambda 语法(从 此示例 中获取):

List<X> xList = new ArrayList<>();
List<Y> yList = xList
        .stream()
        .map(n -> someTransformFunc(n))
        .collect(Collectors.toList());

4

在Java 8风格下,IntelliJ IDEA帮助了我:

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

0
假设有两个可以相互转换的对象,Coach 和 EntityBase。
1. 声明泛型方法。
   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.调用这个方法

  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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接