java - मैं जावा में दो सूचियों में कैसे शामिल हूं?


शर्तें: मूल सूचियों को संशोधित न करें; केवल जेडीके, कोई बाहरी पुस्तकालय नहीं एक-लाइनर या जेडीके 1.3 संस्करण के लिए बोनस अंक।

क्या इससे कोई आसान तरीका है:

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


Answers



मेरे सिर के ऊपर से, मैं इसे एक पंक्ति से छोटा कर सकता हूँ:

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



जावा 8 में:

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






संभवतः सरल नहीं है, लेकिन पेचीदा और बदसूरत:

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



यह प्रश्न मिला है कि सूचियों की मनमाना राशि को जोड़ने के लिए, बाह्य पुस्तकालयों को ध्यान में रखते हुए नहीं। तो, शायद यह किसी और को मदद करेगा:

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

यदि आप एक ही तर्क के लिए विभिन्न संग्रहों के एक नंबर () के लिए आवेदन करना चाहते हैं तो उपयोगी है।




एक और जावा 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());



यह सरल और सिर्फ एक पंक्ति है, लेकिन सूची की सामग्री को सूची में दो जोड़ देगा क्या आपको सचमुच सामग्री तीसरी सूची में डालनी है?

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



थोड़ा छोटा होगा:

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



यहां दो पंक्तियों का उपयोग करते हुए जावा 8 समाधान है:

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

ध्यान रखें कि इस पद्धति का उपयोग नहीं किया जाना चाहिए यदि

  • newList की उत्पत्ति ज्ञात नहीं है और यह पहले से ही अन्य धागे के साथ साझा किया जा सकता है
  • धारा जो newList को संशोधित newList वह एक समानांतर स्ट्रीम है और newList तक पहुंच सिंक्रनाइज़ या newList नहीं है

पक्ष प्रभाव विचारों के कारण

उपर्युक्त दोनों शर्तें दो सूचियों में शामिल होने के उपरोक्त मामले के लिए आवेदन नहीं करती हैं, इसलिए यह सुरक्षित है

इस उत्तर के आधार पर एक अन्य प्रश्न के लिए।




थोड़ा सा सरल:

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



अगर लक्ष्य सूची पूर्ववर्ती है तो आप एक इनेलाइनर कर सकते हैं।

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



प्रस्तावित समाधान तीन सूचियों के लिए है, हालांकि इसे दो सूचियों के लिए भी लागू किया जा सकता है। जावा 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 स्ट्रीम बनाता है जिसके तत्व दूसरे स्ट्रीम के सभी तत्वों के बाद पहली स्ट्रीम के सभी तत्व हैं जैसा कि हमारे पास तीन सूचियां हैं हमने इस पद्धति ( Stream.concat ) को दो बार इस्तेमाल किया है

हम एक ऐसी विधि के साथ एक उपयोगिता वर्ग (स्ट्रिंग यूटिलस) भी लिख सकते हैं जो किसी भी संख्या में सूचियों को लेता है ( वीरगार्ड्स का उपयोग करके) और एक सम्बद्ध सूची को वापस लौटाता है:

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

इसके बाद हम इस पद्धति का उपयोग कर सकते हैं:

List<String> result3 = StringUtils.concatenatedList(list1,list2,list3);



जावा 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]



मेरी राय में सबसे चतुर:

/**
 * @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;
}



ऑब्जेक्ट कुंजी से जुड़ने के लिए समर्थन के साथ जावा 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 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);



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



मैं यह दावा नहीं कर रहा हूं कि यह आसान है, लेकिन आपने एक लाइनर के लिए बोनस का उल्लेख किया ;-)

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



यहां धाराओं और जावा 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());
}



List<?> newList = ListUtils.combine(list1, list2);

ओह, आप को combine विधि लागू करना है :-)




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

}

}



मैं सामान्य तरीके से दो-लाइनर में अपनी स्वयं की उपयोगिता पद्धति को लागू किए बिना सुधार नहीं कर सकता, लेकिन यदि आपके पास स्ट्रिंग्स की सूची है और आप उन तारों को ग्रहण करने के लिए तैयार हैं, तो इनके बिना कॉमा को शामिल किया जा सकता है, आप इस लंबे समय तक खींच सकते हैं -liner:

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

यदि आप जेनेरिक को छोड़ देते हैं, तो यह JDK 1.4 अनुरूप होना चाहिए (हालांकि मैंने इसका परीक्षण नहीं किया है)। इसके अलावा उत्पादन कोड ;-) के लिए अनुशंसित नहीं