将一种元素类型的列表转换为另一种类型的列表

发布于 2024-08-24 07:53:46 字数 288 浏览 3 评论 0原文

我正在编写一个适配器框架,需要将对象列表从一个类转换为另一个类。我可以迭代源列表来执行此操作,如

Java:最佳方式转换 Listto List

但是,我想知道是否有一种方法可以在迭代目标列表时动态执行此操作,这样我就不必迭代列表两次。

I'm writing an adapter framework where I need to convert a list of objects from one class to another. I can iterate through the source list to do this as in

Java: Best way of converting List<Integer> to List<String>

However, I'm wondering if there is a way to do this on the fly when the target list is being iterated, so I don't have to iterate through the list twice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

淡忘如思 2024-08-31 07:53:46

Java 8 方式:

List<String> original = ...;
List<Wrapper> converted = original.stream().map(Wrapper::new).collect(Collectors.toList());

假设 Wrapper 类有一个接受 String 的构造函数。

Java 8 way:

List<String> original = ...;
List<Wrapper> converted = original.stream().map(Wrapper::new).collect(Collectors.toList());

assuming Wrapper class has a constructor accepting a String.

何以笙箫默 2024-08-31 07:53:46

我对该问题的答案适用于您情况:

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

转换后的列表是原始集合的视图,因此当访问目标 List 时会发生转换。

My answer to that question applies to your case:

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

The transformed list is a view on the original collection, so the transformation happens when the destination List is accessed.

孤独患者 2024-08-31 07:53:46

作为迭代器模式的替代方案,您可以使用抽象通用映射器类,并且仅重写转换方法:

  1. 为任何数据类型创建通用集合映射器
  2. [可选]创建在不同数据类型之间转换的方法库(并重写方法)
  3. 使用该库

实现:

// Generic class to transform collections
public abstract class CollectionTransformer<E, F> {

    abstract F transform(E e);

    public List<F> transform(List<E> list) {
        List<F> newList = new ArrayList<F>();
        for (E e : list) {
            newList.add(transform(e));
        }
        return newList;
    }
}

// Method that transform Integer to String
// this override the transform method to specify the transformation
public static List<String> mapIntegerToStringCollection(List<Integer> list) {

    CollectionTransformer transformer = new CollectionTransformer<Integer, String>() {
        @Override  
        String transform(Integer e) {
            return e.toString();
        }
    };
    return transformer.transform(list);
}

// Example Usage
List<Integer> integers = Arrays.asList(1,2);
List<String> strings = mapIntegerToStringCollection(integers);

这很有用,因为您每次都必须使用转换来封装流程。
因此,您可以非常轻松地创建集合映射器库。

As an alternative to the iterator pattern, you can use a abstract generic mapper class, and only override the transform method:

  1. create a generic collection mapper for any data type
  2. [optional] create a library of methods that transform between different data types (and override the method)
  3. use that library

the implementation:

// Generic class to transform collections
public abstract class CollectionTransformer<E, F> {

    abstract F transform(E e);

    public List<F> transform(List<E> list) {
        List<F> newList = new ArrayList<F>();
        for (E e : list) {
            newList.add(transform(e));
        }
        return newList;
    }
}

// Method that transform Integer to String
// this override the transform method to specify the transformation
public static List<String> mapIntegerToStringCollection(List<Integer> list) {

    CollectionTransformer transformer = new CollectionTransformer<Integer, String>() {
        @Override  
        String transform(Integer e) {
            return e.toString();
        }
    };
    return transformer.transform(list);
}

// Example Usage
List<Integer> integers = Arrays.asList(1,2);
List<String> strings = mapIntegerToStringCollection(integers);

This would be useful is you have to use transformations every time, encapsulating the process.
So you can make a library of collection mappers very easy.

半边脸i 2024-08-31 07:53:46

如果您试图获取列表中的元素列表,请使用下面的代码。这里的对象列表包含属性名称,下面为您提供该列表中的名称列表

inputList.stream().map(p -> p.getName()).collect(Collectors.toList());

If you are trying to get a list of elements within a list then use the below code.Here the list of objects contains attribute name and below gets you list of names from that list

inputList.stream().map(p -> p.getName()).collect(Collectors.toList());
著墨染雨君画夕 2024-08-31 07:53:46

您可以编写一个映射迭代器来装饰现有迭代器并对其应用函数。在这种情况下,该函数将对象从一种类型“即时”转换为另一种类型。

像这样的事情:

import java.util.*;

abstract class Transformer<T, U> implements Iterable<U>, Iterator<U> {
    public abstract U apply(T object);  

    final Iterator<T> source;       
    Transformer(Iterable<T> source)    { this.source = source.iterator(); }

    @Override public boolean hasNext() { return source.hasNext(); }
    @Override public U next()          { return apply(source.next()); }
    @Override public void remove()     { source.remove(); } 

    public Iterator<U> iterator()      { return this; }
}

public class TransformingIterator { 
    public static void main(String args[]) {
        List<String> list = Arrays.asList("1", "2", "3");
        Iterable<Integer> it = new Transformer<String, Integer>(list) {
            @Override public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };
        for (int i : it) {
            System.out.println(i);
        }
    }
}

You can write a mapping iterator that decorates an existing iterator and applies a function on it. In this case, the function transforms the objects from one type to another "on-the-fly".

Something like this:

import java.util.*;

abstract class Transformer<T, U> implements Iterable<U>, Iterator<U> {
    public abstract U apply(T object);  

    final Iterator<T> source;       
    Transformer(Iterable<T> source)    { this.source = source.iterator(); }

    @Override public boolean hasNext() { return source.hasNext(); }
    @Override public U next()          { return apply(source.next()); }
    @Override public void remove()     { source.remove(); } 

    public Iterator<U> iterator()      { return this; }
}

public class TransformingIterator { 
    public static void main(String args[]) {
        List<String> list = Arrays.asList("1", "2", "3");
        Iterable<Integer> it = new Transformer<String, Integer>(list) {
            @Override public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };
        for (int i : it) {
            System.out.println(i);
        }
    }
}
匿名。 2024-08-31 07:53:46

Lambdaj 允许以非常简单且易读的方式执行此操作。例如,假设您有一个整数列表,并且想要将它们转换为相应的字符串表示形式,您可以编写类似的内容;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
});

Lambdaj 仅在您迭代结果时应用转换函数。
还有一种更简洁的方法来使用相同的功能。下一个示例假设您有一个具有 name 属性的人员列表,并且您希望在人员姓名的迭代器中转换该列表。

Iterator<String> namesIterator = convertIterator(persons, on(Person.class).getName());

很容易。不是吗?

Lambdaj allows to do that in a very simple and readable way. For example, supposing you have a list of Integer and you want to convert them in the corresponding String representation you could write something like that;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
});

Lambdaj applies the conversion function only while you're iterating on the result.
There is also a more concise way to use the same feature. The next example works supposing that you have a list of persons with a name property and you want to convert that list in an iterator of person's names.

Iterator<String> namesIterator = convertIterator(persons, on(Person.class).getName());

Pretty easy. Isn't it?

守护在此方 2024-08-31 07:53:46

这可能是一个解决方案 -->通过使用地图

List<Employee> employee = Arrays.asList(new Emp(1, 100), new Emp(2, 200), new Emp(3, 300));
List<Employee> employeS = employee.stream()
                                             .map(emp -> new Emp(emp.getId(), emp.getSalary * 100))
                                             .collect(Collectors.toList());
employeS .stream() .forEach(s -> System.out.println("Id :" + s.getId() + " Salary :" + s.getSalary()));

This Could be a solutions --> by using map

List<Employee> employee = Arrays.asList(new Emp(1, 100), new Emp(2, 200), new Emp(3, 300));
List<Employee> employeS = employee.stream()
                                             .map(emp -> new Emp(emp.getId(), emp.getSalary * 100))
                                             .collect(Collectors.toList());
employeS .stream() .forEach(s -> System.out.println("Id :" + s.getId() + " Salary :" + s.getSalary()));
始终不够爱げ你 2024-08-31 07:53:46

该问题不会重复列表两次。它只迭代一次,并且是迄今为止唯一已知的方法。

您也可以在 google-collections 的 commons-collections 中使用一些转换器类,但它们都在幕后做同样的事情:)以下是一种方法

CollectionUtils.collect(collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer());

That question does not iterate through the list twice. It just iterates once and by far is the only known method.

Also you could use some transformer classes in commons-collections of google-collections but they all do the same thing under the hood :) the following being one way

CollectionUtils.collect(collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer());
甜心 2024-08-31 07:53:46

那么,您可以创建自己的迭代器包装类来执行此操作。但我怀疑这样做是否能节省很多钱。

下面是一个简单的示例,它将任何迭代器包装为 String 迭代器,使用 Object.toString() 进行映射。

public MyIterator implements Iterator<String> {

    private Iterator<? extends Object> it;

    public MyIterator(Iterator<? extends Object> it) {
        this.it = it;
    }

    public boolean hasNext() {
        return it.hasNext();
    }

    public String next() {
        return it.next().toString();
    }

    public void remove() {
        it.remove();
    }
}

Well, you could create your own iterator wrapper class to do this. But I doubt that you would save much by doing this.

Here's a simple example that wraps any iterator to a String iterator, using Object.toString() to do the mapping.

public MyIterator implements Iterator<String> {

    private Iterator<? extends Object> it;

    public MyIterator(Iterator<? extends Object> it) {
        this.it = it;
    }

    public boolean hasNext() {
        return it.hasNext();
    }

    public String next() {
        return it.next().toString();
    }

    public void remove() {
        it.remove();
    }
}
独木成林 2024-08-31 07:53:46

我认为您必须创建一个自定义列表(实现列表接口)或一个自定义迭代器。例如:

ArrayList<String> targetList = new ArrayList<String>();
ConvertingIterator<String> iterator = new ConvertingIterator<String>(targetList);
// and here you would have to use a custom List implementation as a source List
// using the Iterator created above

但我怀疑这种方法能否为您节省很多。

I think you would either have to create a custom List (implementing the List interface) or a custom Iterator. For example:

ArrayList<String> targetList = new ArrayList<String>();
ConvertingIterator<String> iterator = new ConvertingIterator<String>(targetList);
// and here you would have to use a custom List implementation as a source List
// using the Iterator created above

But I doubt that this approach would save you much.

芸娘子的小脾气 2024-08-31 07:53:46

这是一种即时方法。 (jdk中肯定已经有类似的东西;我只是找不到它。)

  package com.gnahraf.util;

  import java.util.AbstractList;
  import java.util.List;
  import java.util.Objects;
  import java.util.function.Function;

  /**
   * 
   */
  public class Lists {

    private Lists() { }


    public static <U,V> List<V> transform(List<U> source, Function<U, V> mapper) {
      return new ListView<U, V>(source, mapper);
    }

    protected static class ListView<U, V> extends AbstractList<V> {

      private final List<U> source;
      private final Function<U, V> mapper;

      protected ListView(List<U> source, Function<U, V> mapper) {
        this.source = Objects.requireNonNull(source, "source");
        this.mapper = Objects.requireNonNull(mapper, "mapper");
      }

      @Override
      public V get(int index) {
        return mapper.apply(source.get(index));
      }

      @Override
      public int size() {
        return source.size();
      }

    }

  }

Here's an on-the-fly approach. (There must be something already like this in the jdk; I just can't find it.)

  package com.gnahraf.util;

  import java.util.AbstractList;
  import java.util.List;
  import java.util.Objects;
  import java.util.function.Function;

  /**
   * 
   */
  public class Lists {

    private Lists() { }


    public static <U,V> List<V> transform(List<U> source, Function<U, V> mapper) {
      return new ListView<U, V>(source, mapper);
    }

    protected static class ListView<U, V> extends AbstractList<V> {

      private final List<U> source;
      private final Function<U, V> mapper;

      protected ListView(List<U> source, Function<U, V> mapper) {
        this.source = Objects.requireNonNull(source, "source");
        this.mapper = Objects.requireNonNull(mapper, "mapper");
      }

      @Override
      public V get(int index) {
        return mapper.apply(source.get(index));
      }

      @Override
      public int size() {
        return source.size();
      }

    }

  }
愿与i 2024-08-31 07:53:46

这种转换复杂对象类型的方式非常简单直观,并且将来可以轻松修改。

 class Model {
    private int start;
    private int end;
    private String type;
    //other variables  
    //acccessors , constructors etc
}**

Say we need to convert this object into another one
listed below. Add a constructor with Model object


class TransformModel {
    private int start;
    private int end;
    private String type;

    TransformeModel(Model model) {
        this.start = model.start;
        this.end = model.end;
        this.type = model.type;
    }**

    public List<TransformModel> convertFromModel(List<Model> models) {
        return models.stream().map(TransformModel::new).collect(Collectors.toList());
    }
}

This way of transforming complex object types is very simple and intuitive and can be easily modified in future.

 class Model {
    private int start;
    private int end;
    private String type;
    //other variables  
    //acccessors , constructors etc
}**

Say we need to convert this object into another one
listed below. Add a constructor with Model object


class TransformModel {
    private int start;
    private int end;
    private String type;

    TransformeModel(Model model) {
        this.start = model.start;
        this.end = model.end;
        this.type = model.type;
    }**

    public List<TransformModel> convertFromModel(List<Model> models) {
        return models.stream().map(TransformModel::new).collect(Collectors.toList());
    }
}
陌上青苔 2024-08-31 07:53:46

要构建 Alexey Malev对此线程的第一个回答,他们的答案对我有用,但我使用了 Java 21 版本:

List<YourClass> yourClass = myClass.stream().map(YourClass::new).toList();

这是为了将 MyClass 类型的列表转换为 YourClass 类型的列表,并且列表中的内容相同。您还需要在 YourClass 中添加一个构造函数,该构造函数接受 MyClass 对象作为参数,您可以在其中执行如下操作:

public YourClass(MyClass myClass){
   this.attribute1 = myClass.item1;
   this.attribute2 = myClass.item2;
}

To build off of the first answer to this thread by Alexey Malev , their answer worked for me, but I used the Java 21 version:

List<YourClass> yourClass = myClass.stream().map(YourClass::new).toList();

This is for converting the List of type MyClass to be a List of type YourClass with the same contents in the list. You will also need to add a constructor in YourClass that takes in MyClass object as a parameter where you can do something like the following:

public YourClass(MyClass myClass){
   this.attribute1 = myClass.item1;
   this.attribute2 = myClass.item2;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文