programing

Java에서 두 목록을 어떻게 결합합니까?

nasanasas 2020. 9. 30. 10:58
반응형

Java에서 두 목록을 어떻게 결합합니까?


조건 : 원래 목록을 수정하지 마십시오. JDK 전용, 외부 라이브러리 없음. 한 줄짜리 또는 JDK 1.3 버전에 대한 보너스 포인트.

다음보다 더 간단한 방법이 있습니까?

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);

머리 꼭대기에서 한 줄로 줄일 수 있습니다.

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

Java 8에서

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());

Apache commons-collections 라이브러리를 사용할 수 있습니다 .

List<String> newList = ListUtils.union(list1, list2);

아마도 더 간단하지는 않지만 흥미롭고 추악합니다.

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

프로덕션 코드에서 사용하지 마십시오 ...;)


요구 사항 중 하나는 원본 목록을 보존하는 것입니다. 새 목록을 만들고를 사용하면 목록 addAll()에있는 개체에 대한 참조 수가 두 배로 늘어납니다. 목록이 매우 큰 경우 메모리 문제가 발생할 수 있습니다.

연결된 결과를 수정할 필요가없는 경우 사용자 지정 목록 구현을 사용하여이를 방지 할 수 있습니다. 사용자 정의 구현 클래스는 분명히 한 줄 이상이지만 ... 사용하는 것은 짧고 달콤합니다.

CompositeUnmodifiableList.java :

public class CompositeUnmodifiableList<E> extends AbstractList<E> {

    private final List<E> list1;
    private final List<E> list2;

    public CompositeUnmodifiableList(List<E> list1, List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(int index) {
        if (index < list1.size()) {
            return list1.get(index);
        }
        return list2.get(index-list1.size());
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }
}

용법:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);

더 간단하지는 않지만 크기 조정 오버 헤드가 없습니다.

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);

또 다른 Java 8 한 줄짜리 :

List<String> newList = Stream.of(listOne, listTwo)
                             .flatMap(x -> x.stream())
                             .collect(Collectors.toList());

보너스로 Stream.of()는 가변적 이기 때문에 원하는만큼 목록을 연결할 수 있습니다.

List<String> newList = Stream.of(listOne, listTwo, listThree)
                             .flatMap(x -> x.stream())
                             .collect(Collectors.toList());

이 질문은 외부 라이브러리를 고려하지 않고 임의의 양의 목록을 연결하려는 것을 찾았습니다. 따라서 아마도 다른 사람에게 도움이 될 것입니다.

com.google.common.collect.Iterables#concat()

하나의 for ()에있는 여러 다른 컬렉션에 동일한 논리를 적용하려는 경우 유용합니다.


다음은 두 줄을 사용하는 Java 8 솔루션입니다.

List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);

다음과 같은 경우이 방법을 사용해서는 안됩니다.

  • 출처를 newList알 수 없으며 이미 다른 스레드와 공유되었을 수 있습니다.
  • 수정하는 스트림이 newList병렬 스트림이고 액세스 newList가 동기화되지 않거나 스레드로부터 안전하지 않습니다.

부작용 고려 사항으로 인해.

위의 두 가지 목록을 결합하는 경우 위의 두 조건이 모두 적용되지 않으므로 안전합니다.

다른 질문 에 대한 이 답변기반으로 합니다 .


이것은 간단하고 한 줄에 불과하지만 listTwo의 내용을 listOne에 추가합니다. 정말로 내용을 세 번째 목록에 넣어야합니까?

Collections.addAll(listOne, listTwo.toArray());

제안 된 솔루션은 두 개의 목록에도 적용될 수 있지만 세 개의 목록에 대한 것입니다. Java 8에서는 Stream.of 또는 Stream.concat 을 다음과 같이 사용할 수 있습니다 .

List<String> result1 = Stream.concat(Stream.concat(list1.stream(),list2.stream()),list3.stream()).collect(Collectors.toList());
List<String> result2 = Stream.of(list1,list2,list3).flatMap(Collection::stream).collect(Collectors.toList());

Stream.concat두 개의 스트림을 입력으로 취하고 첫 번째 스트림의 모든 요소와 두 번째 스트림의 모든 요소가 뒤 따르는 요소가있는 느리게 연결된 스트림을 만듭니다. 세 개의 목록이 있으므로이 방법 ( Stream.concat)을 두 번 사용했습니다.

임의의 수의 목록 ( varargs 사용 ) 을 취하고 연결된 목록을 다음과 같이 반환하는 메서드로 유틸리티 클래스를 작성할 수도 있습니다 .

public static <T> List<T> concatenateLists(List<T>... collections) {
        return Arrays.stream(collections).flatMap(Collection::stream).collect(Collectors.toList()); 
}

그런 다음이 방법을 다음과 같이 사용할 수 있습니다.

List<String> result3 = Utils.concatenateLists(list1,list2,list3);

약간 더 간단합니다.

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

조금 더 짧을 것입니다.

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

대상 목록이 미리 선언 된 경우 oneliner를 수행 할 수 있습니다.

(newList = new ArrayList<String>(list1)).addAll(list2);

일반 Java 8 유틸리티 메서드를 만들어 원하는 수의 목록을 연결할 수 있습니다 .

@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
    return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}

솔루션이 이미 게시되었으므로 Java8스트림 을 사용하는 또 다른 하나의 라이너 솔루션 flatMap입니다.flatMap

List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);

또는

List<E> ints = Stream.of(list1, list2).collect(ArrayList::new, List::addAll, List::addAll);

암호

    List<List<Integer>> lol = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
    List<Integer> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
    System.out.println(lol);
    System.out.println(li);

산출

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]

에서 자바 8 (다른 방법) :

List<?> newList = 
Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList());

내 생각에 가장 똑똑한 사람 :

/**
 * @param smallLists
 * @return one big list containing all elements of the small ones, in the same order.
 */
public static <E> List<E> concatenate (final List<E> ... smallLists)
{
    final ArrayList<E> bigList = new ArrayList<E>();
    for (final List<E> list: smallLists)
    {
        bigList.addAll(list);
    }
    return bigList;
}

정적 가져 오기 및 도우미 클래스를 사용하여 수행 할 수 있습니다.

nb 이 클래스의 생성이 개선 될 수 있습니다.

public class Lists {

   private Lists() { } // can't be instantiated

   public static List<T> join(List<T>... lists) {
      List<T> result = new ArrayList<T>();
      for(List<T> list : lists) {
         result.addAll(list);
      }
      return results;
   }

}

그런 다음 다음과 같은 일을 할 수 있습니다.

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);

객체 키로 결합을 지원하는 Java 8 버전 :

public List<SomeClass> mergeLists(final List<SomeClass> left, final List<SomeClass> right, String primaryKey) {
    final Map<Object, SomeClass> mergedList = new LinkedHashMap<>();

    Stream.concat(left.stream(), right.stream())
        .map(someObject -> new Pair<Object, SomeClass>(someObject.getSomeKey(), someObject))
        .forEach(pair-> mergedList.put(pair.getKey(), pair.getValue()));

    return new ArrayList<>(mergedList.values());
}

Helper 클래스를 사용하십시오.

나는 제안한다 :

public static <E> Collection<E> addAll(Collection<E> dest, Collection<? extends E>... src) {
    for(Collection<? extends E> c : src) {
        dest.addAll(c);
    }

    return dest;
}

public static void main(String[] args) {
    System.out.println(addAll(new ArrayList<Object>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    // does not compile
    // System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList(4, 5, 6)));
}

public static <T> List<T> merge(List<T>... args) {
    final List<T> result = new ArrayList<>();

    for (List<T> list : args) {
        result.addAll(list);
    }

    return result;
}

public static <T> List<T> merge(@Nonnull final List<T>... list) {
    // calculate length first
    int mergedLength = 0;
    for (List<T> ts : list) {
      mergedLength += ts.size();
    }

    final List<T> mergedList = new ArrayList<>(mergedLength);

    for (List<T> ts : list) {
      mergedList.addAll(ts);
    }

    return mergedList;
  }

나는 그것이 간단하다고 주장하는 것이 아니라 한 줄에 대한 보너스를 언급했습니다 ;-)

Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))

한 줄에 가깝지는 않지만 이것이 가장 간단하다고 생각합니다.

List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);

for(String w:newList)
        System.out.printf("%s ", w);

목록에 다른 유형이 있고이를 다른 유형의 목록에 결합하려는 경우 스트림과 Java 8을 사용하는 방법이 있습니다.

public static void main(String[] args) {
    List<String> list2 = new ArrayList<>();
    List<Pair<Integer, String>> list1 = new ArrayList<>();

    list2.add("asd");
    list2.add("asdaf");
    list1.add(new Pair<>(1, "werwe"));
    list1.add(new Pair<>(2, "tyutyu"));

    Stream stream = Stream.concat(list1.stream(), list2.stream());

    List<Pair<Integer, String>> res = (List<Pair<Integer, String>>) stream
            .map(item -> {
                if (item instanceof String) {
                    return new Pair<>(0, item);
                }
                else {
                    return new Pair<>(((Pair<Integer, String>)item).getKey(), ((Pair<Integer, String>)item).getValue());
                }
            })
            .collect(Collectors.toList());
}

이 작업을 정적으로 수행하려면 다음을 수행 할 수 있습니다.

예제에서는 자연 순서 (== Enum-order)의 2 개의 EnumSet를 사용 A, B하고 ALL목록 에서 조인 합니다.

public static final EnumSet<MyType> CATEGORY_A = EnumSet.of(A_1, A_2);
public static final EnumSet<MyType> CATEGORY_B = EnumSet.of(B_1, B_2, B_3);

public static final List<MyType> ALL = 
              Collections.unmodifiableList(
                  new ArrayList<MyType>(CATEGORY_A.size() + CATEGORY_B.size())
                  {{
                      addAll(CATEGORY_A);
                      addAll(CATEGORY_B);
                  }}
              );

import java.util.AbstractList;
import java.util.List;


/**
 * The {@code ConcatList} is a lightweight view of two {@code List}s.
 * <p>
 * This implementation is <em>not</em> thread-safe even though the underlying lists can be.
 * 
 * @param <E>
 *            the type of elements in this list
 */
public class ConcatList<E> extends AbstractList<E> {

    /** The first underlying list. */
    private final List<E> list1;
    /** The second underlying list. */
    private final List<E> list2;

    /**
     * Constructs a new {@code ConcatList} from the given two lists.
     * 
     * @param list1
     *            the first list
     * @param list2
     *            the second list
     */
    public ConcatList(final List<E> list1, final List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(final int index) {
        return getList(index).get(getListIndex(index));
    }

    @Override
    public E set(final int index, final E element) {
        return getList(index).set(getListIndex(index), element);
    }

    @Override
    public void add(final int index, final E element) {
        getList(index).add(getListIndex(index), element);
    }

    @Override
    public E remove(final int index) {
        return getList(index).remove(getListIndex(index));
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }

    @Override
    public boolean contains(final Object o) {
        return list1.contains(o) || list2.contains(o);
    }

    @Override
    public void clear() {
        list1.clear();
        list2.clear();
    }

    /**
     * Returns the index within the corresponding list related to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the index of the underlying list
     */
    private int getListIndex(final int index) {
        final int size1 = list1.size();
        return index >= size1 ? index - size1 : index;
    }

    /**
     * Returns the list that corresponds to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the underlying list that corresponds to that index
     */
    private List<E> getList(final int index) {
        return index >= list1.size() ? list2 : list1;
    }

}

I can't improve on the two-liner in the general case without introducing your own utility method, but if you do have lists of Strings and you're willing to assume those Strings don't contain commas, you can pull this long one-liner:

List<String> newList = new ArrayList<String>(Arrays.asList((listOne.toString().subString(1, listOne.length() - 1) + ", " + listTwo.toString().subString(1, listTwo.length() - 1)).split(", ")));

If you drop the generics, this should be JDK 1.4 compliant (though I haven't tested that). Also not recommended for production code ;-)


public class TestApp {

/**
 * @param args
 */
public static void main(String[] args) {
    System.out.println("Hi");
    Set<List<String>> bcOwnersList = new HashSet<List<String>>();
    List<String> bclist = new ArrayList<String>();
    List<String> bclist1 = new ArrayList<String>();
    List<String> object = new ArrayList<String>();
    object.add("BC11");
    object.add("C2");
    bclist.add("BC1");
    bclist.add("BC2");
    bclist.add("BC3");
    bclist.add("BC4");
    bclist.add("BC5");
    bcOwnersList.add(bclist);
    bcOwnersList.add(object);

    bclist1.add("BC11");
    bclist1.add("BC21");
    bclist1.add("BC31");
    bclist1.add("BC4");
    bclist1.add("BC5");

    List<String> listList= new ArrayList<String>();
    for(List<String> ll : bcOwnersList){
        listList = (List<String>) CollectionUtils.union(listList,CollectionUtils.intersection(ll, bclist1));
    }
    /*for(List<String> lists : listList){
        test = (List<String>) CollectionUtils.union(test, listList);
    }*/
    for(Object l : listList){
        System.out.println(l.toString());
    }
    System.out.println(bclist.contains("BC"));

}

}

참고URL : https://stackoverflow.com/questions/189559/how-do-i-join-two-lists-in-java

반응형