शर्तें: मूल सूचियों को संशोधित नहीं करना; JDK केवल, कोई बाहरी लाइब्रेरी नहीं। एक-लाइनर या जेडीके 1.3 संस्करण के लिए बोनस अंक।
क्या इससे सरल तरीका है:
List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
शर्तें: मूल सूचियों को संशोधित नहीं करना; JDK केवल, कोई बाहरी लाइब्रेरी नहीं। एक-लाइनर या जेडीके 1.3 संस्करण के लिए बोनस अंक।
क्या इससे सरल तरीका है:
List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
जवाबों:
जावा 8 में:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
.collect(Collectors.toList());
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).distinct().collect(Collectors.toList());
Stream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toList())
मेरे सिर के ऊपर से, मैं इसे एक पंक्ति से छोटा कर सकता हूं:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
addAll()
दोनों का निर्माण किया। मैंने उन सभी को आज़माया जो सूचियों की नकल नहीं करने का सुझाव देते हैं और उनके परिणामस्वरूप बहुत अधिक ओवरहेड होता है जिसकी हमें इस समय ज़रूरत नहीं थी।
addAll(Collection)
एक रिटर्न boolean
।
आप अपाचे कॉमन्स-संग्रह पुस्तकालय का उपयोग कर सकते हैं :
List<String> newList = ListUtils.union(list1, list2);
आपकी आवश्यकताओं में से एक मूल सूचियों को संरक्षित करना है। यदि आप एक नई सूची बनाते हैं और उपयोग करते हैं 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);
Collections.unmodifiableList()
विधि के समान कुछ करने के रूप में देखता हूं , जो इसे अपरिवर्तनीय बनाने के लिए एक सूची लपेटता है। CompositeUnmodifiableList
एक ही काम करता है, सिवाय इसके कि दो सूचियों को लपेटता है और एक संक्षिप्त दृश्य प्रदान करता है। आपके द्वारा किए गए सभी बिंदु CompositeUnmodifiableList
सही भी हैं Collections.unmodifiableList()
।
List<? extends E>
शायद सरल नहीं है, लेकिन पेचीदा और बदसूरत:
List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };
इसे उत्पादन कोड में उपयोग न करें ...;)
एक और जावा 8 एक-लाइनर:
List<String> newList = Stream.of(listOne, listTwo)
.flatMap(Collection::stream)
.collect(Collectors.toList());
एक बोनस के रूप में, चूंकि Stream.of()
परिवर्तनशील है, आप जितनी चाहें उतनी सूचियों को संक्षिप्त कर सकते हैं।
List<String> newList = Stream.of(listOne, listTwo, listThree)
.flatMap(Collection::stream)
.collect(Collectors.toList());
x -> x.stream()
के साथ प्रतिस्थापित किया जा सकता है Collection::stream
।
List::stream
।
यह प्रश्न मिला कि बाहरी पुस्तकालयों को ध्यान में न रखते हुए, सूचियों की मनमानी राशि को प्राप्त करना। तो, शायद यह किसी और की मदद करेगा:
com.google.common.collect.Iterables#concat()
उपयोगी है यदि आप एक ही तर्क को कई संग्रह में एक (एक) के लिए लागू करना चाहते हैं।
com.google.common.collect.Iterators#concat(java.util.Iterator<? extends java.util.Iterator<? extends T>>)
इसके बजाय कॉल करना चाहिए Iterables#concat()
; क्योंकि बाद में अभी भी अस्थायी लिंक में तत्वों की नकल!
जावा 8 (
Stream.of
औरStream.concat
)
प्रस्तावित समाधान तीन सूचियों के लिए है, हालांकि इसे दो सूचियों के लिए भी लागू किया जा सकता है। 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);
यहां दो लाइनों का उपयोग करके एक जावा 8 समाधान दिया गया है:
List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);
ध्यान रखें कि यदि इस विधि का उपयोग नहीं किया जाना चाहिए
newList
ज्ञात नहीं है और यह पहले से ही अन्य थ्रेड्स के साथ साझा किया जा सकता हैnewList
वह एक समानांतर स्ट्रीम है और उस तक पहुंच newList
सिंक्रनाइज़ या थ्रेडसेफ़ नहीं हैसाइड इफेक्ट विचार के कारण।
उपरोक्त दोनों शर्तें दो सूचियों में शामिल होने के उपरोक्त मामले के लिए लागू नहीं होती हैं, इसलिए यह सुरक्षित है।
इस सवाल के जवाब के आधार पर ।
newList
किसी अन्य सूत्र द्वारा अवलोकन नहीं किया जाता है। लेकिन आप सही हैं कि यह संभवतया नहीं किया जाना चाहिए अगर यह अज्ञात है जहां से newList
आया मूल्य (उदाहरण के लिए यदि newList
एक पैरामीटर के रूप में पारित किया गया था।
.forEach(newList::addAll);
इसके बजाय क्यों .collect(Collectors.toList());
?
List<List<Object>>
। आपके मन में कुछ इस तरह से हो सकता है: stackoverflow.com/questions/189559/…
flatMap
।
यह सरल और सिर्फ एक पंक्ति है, लेकिन सूची के अवयवों को सूची में जोड़ देगा। क्या आपको वास्तव में सामग्री को तीसरी सूची में रखने की आवश्यकता है?
Collections.addAll(listOne, listTwo.toArray());
थोड़ा सरल:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
List
संरचना कोई विशिष्टता की कमी लगाता है। आप सेट के साथ एक ही काम करके दुपट्टे को हटा सकते हैं। Set<String> newSet = new HashSet<>(setOne); newSet.addAll(setTwo);
आप किसी भी संख्या को सूचीबद्ध करने के लिए अपना जेनेरिक जावा 8 उपयोगिता विधि बना सकते हैं ।
@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}
में जावा 8 (दूसरा रास्ता):
List<?> newList =
Stream.of(list1, list2).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]
flatMap
, क्योंकि सूची केवल एक बार एकत्र होने पर पुनरावृत्त होती है
मेरी राय में सबसे चतुर:
/**
* @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;
}
@SafeVarargs
!
आप इसे स्टैटिक इम्पोर्ट और हेल्पर क्लास के साथ कर सकते हैं
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);
ऑब्जेक्ट कुंजी से जुड़ने के लिए समर्थन के साथ जावा 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());
}
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 <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(@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;
}
हम 2 दृष्टिकोणों के साथ j88 का उपयोग करके 2 सूचियों में शामिल हो सकते हैं।
List<String> list1 = Arrays.asList("S", "T");
List<String> list2 = Arrays.asList("U", "V");
1) समवर्ती का उपयोग करना:
List<String> collect2 = Stream.concat(list1.stream(), list2.stream()).collect(toList());
System.out.println("collect2 = " + collect2); // collect2 = [S, T, U, V]
2) फ्लैटपाइप का उपयोग करना:
List<String> collect3 = Stream.of(list1, list2).flatMap(Collection::stream).collect(toList());
System.out.println("collect3 = " + collect3); // collect3 = [S, T, U, V]
लगभग सभी उत्तरों में एक ArrayList का उपयोग करने का सुझाव दिया गया है।
List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);
कुशल ऐड ऑपरेशन के लिए लिंक्डलिस्ट का उपयोग करना पसंद करते हैं।
ArrayList ऐड O (1) amortized है, लेकिन O (n) सबसे खराब स्थिति है क्योंकि सरणी को आकार और कॉपी किया जाना चाहिए। जबकि लिंक्डलिस्ट हमेशा ओ (1) स्थिर होता है।
अधिक जानकारी https://stackoverflow.com/a/322742/311420
मैं यह दावा नहीं कर रहा हूं कि यह सरल है, लेकिन आपने एक-लाइनर्स के लिए बोनस का उल्लेख किया ;-)
Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
new Vector(list1).elements(),
new Vector(list2).elements(),
...
}))
यहां स्ट्रीम और जावा 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- क्रम) में 2 EnumSets का उपयोग करते हैं 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;
}
}