জাভাতে বিপরীত ক্রমে একটি তালিকার মাধ্যমে আইট্রেট করা


251

জেনেরিকের ব্যবহার করতে আমি একটি টুকরো কোড স্থানান্তরিত করছি। এটি করার জন্য একটি যুক্তি হ'ল ফর লুপটি সূচকের উপর নজর রাখার চেয়ে বা স্পষ্টত পুনরুক্তি ব্যবহারকারীর চেয়ে অনেক বেশি পরিষ্কার।

প্রায় অর্ধেক ক্ষেত্রে, তালিকাটি (একটি অ্যারেলিস্ট) আজ সূচক ব্যবহার করে বিপরীত ক্রমে পুনরাবৃত্তি করা হচ্ছে।

কেউ কি indexed for loopএটির পরিষ্কার পদ্ধতিতে পরামর্শ করতে পারেন (যেহেতু সংগ্রহগুলি নিয়ে কাজ করার সময় আমি পছন্দ করি না ) যদিও এটি কাজ করে?

 for (int i = nodes.size() - 1; i >= 0; i--) {
    final Node each = (Node) nodes.get(i);
    ...
 }

দ্রষ্টব্য: আমি জেডিকে বাইরে কোনও নতুন নির্ভরতা যুক্ত করতে পারি না।


10
একটি সূচকযুক্ত ডাটা স্ট্রাকচারের উপরে পুনরাবৃত্তি করার জন্য একটি স্পষ্ট সূচক ব্যবহার সম্পর্কে কী খারাপ? কমপক্ষে এটি আপনাকে দেখায় যে ঠিক কী চলছে। পিছনের দিকে পুনরাবৃত্তি করার জন্য আমি সর্বদা নীচের থেকে কিছুটা ছোট for (int i = nodes.size(); --i >= 0;)
খাটিয়া

4
বিশেষত কিছুই নয়, আমি কেবল একটি ইন্টারফেসে প্রোগ্রাম করব এবং আমি কী ধরণের তালিকা ব্যবহার করছি সে সম্পর্কে জানতাম না। যদিও আপনার ছোট হাতটি আমি খুব পছন্দ করি। (+1 মন্তব্য)
আল্লায় লালনোদে

1
@ x4u: এতে খুব বেশি কিছু নেই যদিও আইট্রেটর ব্যর্থ দ্রুত এবং পুনরাবৃত্তির সময় উপাদানগুলিকে সহজেই সরানোর অনুমতি দেয়।
অ্যাডামস্কি

2
এই শ্রেণিটি নষ্ট হয়ে গেছে, কারণ ব্যবহারকারী একই আইটারেবলের পরে দ্বিতীয়বার পুনরাবৃত্তি করতে চাইতে পারে বা পুনরাবৃত্তিটি যখন তৈরি হবে এবং পুনরাবৃত্তি হবে তখন তালিকার মধ্যে পরিবর্তন হতে পারে। আমি নিশ্চিত আপনার উদ্দেশ্যগুলির জন্য আপনি কেবল এটি না করার বিষয়টি নিশ্চিত করবেন, তবে কোডটি ঠিক করা খুব কঠিন হবে না; অথবা কেবল পেয়ারা থেকে কোড চুরি করুন (অ্যাপাচি ২.০ লাইসেন্স): কোড. google.com/p/guava-libraries/source/browse/trunk/src/com/…
কেভিন

1
যথেষ্ট সুক্ষ্ম, তবে আমি যদি সঠিকভাবে এটি পড়ি তবে পেয়ারা এমনকি একই জিনিসটির জন্য সংবেদনশীল। কোনও ব্যবহারকারী যদি বিপরীত থেকে ফলাফলের অনুলিপি রাখতেন, তবে একই সমস্যা হবে।
আল্লায় লালনডে

উত্তর:


446

এটা চেষ্টা কর:

// Substitute appropriate type.
ArrayList<...> a = new ArrayList<...>();

// Add elements to list.

// Generate an iterator. Start just after the last element.
ListIterator li = a.listIterator(a.size());

// Iterate in reverse.
while(li.hasPrevious()) {
  System.out.println(li.previous());
}

4
খারাপ না. সূচকটি ব্যবহার করে না, তবে প্রতিটি সিনট্যাক্সের জন্য কমনীয়তা হারায়। যাইহোক +1।
আল্লায় লালনোদে

26
সূচকের আর্গুমেন্ট ছাড়াই তালিকার তালিকা (ইট্রেটার) () কল করার পরে তালিকার শুরুতে একটি আইট্রেটর দেবে এবং সুতরাং প্রিরিস () প্রথম কলটিতে মিথ্যা ফিরিয়ে দেবে।
অ্যাডামস্কি

2
আপনি listIteratorকলটিতে একটি সূচি চান , আমার মনে হয়।
টম হাটিন -

1
আপনি এমন একটি লিখতে পারেন Iteratorযা একটি ListIteratorবিপরীত ব্যবহার করে তবে এটি একটি লুপের জন্য উপযুক্ত নাও হতে পারে।
টম হাটিন -

1
এটি একটি লুপ নয়, তাই আমি এটি নিয়ে এসেছি এবং এটি জড়িয়ে রেখেছি। পেস্টবিন.সি.এ .1759041 তাই, এখন আমি করতে পারিfor (Node each : new ListReverse<Node>(nodes)) { }
আল্লায় লালনোদে

35

পেয়ারা অফার Lists#reverse(List)এবং ImmutableList#reverse()। বেশিরভাগ ক্ষেত্রে পেয়ারা হিসাবে, প্রাক্তন প্রতিনিধিরা যদি পরে যুক্তিটি হয় তবে আপনি প্রবীণটিকে ImmutableListসব ক্ষেত্রেই ব্যবহার করতে পারেন। এগুলি তালিকার নতুন অনুলিপি তৈরি করে না তবে এটির "বিপরীত দর্শন"।

উদাহরণ

List reversed = ImmutableList.copyOf(myList).reverse();

23

লুপ সিনট্যাক্সের জন্য এটি ব্যবহার করা সম্ভব বলে আমি মনে করি না। কেবলমাত্র আমি এরকম কিছু করার পরামর্শ দিচ্ছি:

Collections.reverse(list);
for (Object o : list) {
  ...
}

... তবে আমি এটি "ক্লিনার" বলব না যে এটি কম দক্ষ হতে চলেছে।


26
এবং এটি আপনার পরিবর্তিত তালিকার পরিবর্তে পরিবর্তিত হয় যা বেশ বিশাল পার্শ্ব-প্রতিক্রিয়া। (বলুন যে আপনি এটি কোনও পদ্ধতিতে
আবদ্ধ করেন

এটিই সবচেয়ে পরিষ্কার সমাধান।
jfajunior

14

বিকল্প 1: আপনি সংগ্রহগুলি # বিপরীতমুখী () দিয়ে তালিকার বিপরীতকরণ এবং তারপরে ভবিষ্যদ্বাণী ব্যবহার সম্পর্কে চিন্তাভাবনা করেছেন ?

অবশ্যই, আপনি নিজের কোডটিও রিফ্যাক্টর করতে পারেন যাতে তালিকাটি সঠিকভাবে অর্ডার করা হয় যাতে আপনার এটিকে বিপরীত করতে হবে না, যা অতিরিক্ত স্থান / সময় ব্যবহার করে।


সম্পাদনা করুন:

বিকল্প 2: বিকল্পভাবে, আপনি অ্যারেলিস্টের পরিবর্তে একটি ডেক ব্যবহার করতে পারেন ? এটি আপনাকে এগিয়ে এবং পিছনের দিকে পুনরাবৃত্তি করার অনুমতি দেবে


সম্পাদনা করুন:

বিকল্প 3: অন্যরা যেমন পরামর্শ দিয়েছে, আপনি এমন একজন ইট্রেটর লিখতে পারেন যা তালিকার বিপরীতে চলে যাবে, এখানে একটি উদাহরণ রয়েছে:

import java.util.Iterator;
import java.util.List;

public class ReverseIterator<T> implements Iterator<T>, Iterable<T> {

    private final List<T> list;
    private int position;

    public ReverseIterator(List<T> list) {
        this.list = list;
        this.position = list.size() - 1;
    }

    @Override
    public Iterator<T> iterator() {
        return this;
    }

    @Override
    public boolean hasNext() {
        return position >= 0;
    }

    @Override
    public T next() {
        return list.get(position--);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

}


List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");

for (String s : new ReverseIterator<String>(list)) {
    System.out.println(s);
}

1
এটি সম্পর্কে চিন্তাভাবনা করেছেন, তবে এটির বিপরীতে ব্যয় করা নিষিদ্ধ। এছাড়াও, এটির জন্য এই জাতীয় পুনরাবৃত্তির প্রায় অর্ধেক সময় প্রয়োজন। এটি উল্টানো সমস্যাটি কেবল অন্য অর্ধে নিয়ে যায়।
আল্লায় লালনোদে

3
+ ডেকের জন্য; সাধারণ বাস্তবায়ন আছে descendingIterator()
ট্র্যাশগোড

লিঙ্কযুক্ত তালিকার জন্য এটি ভয়ানক সঞ্চালন করবে, ওপিটির রূপটি আরও ভাল।
মাস্টারেক্সিলো

1
একটি for eachঅভিব্যক্তি ব্যবহার করা আমার মতে সর্বাধিক অভিহিত সমাধান solution আপনার তালিকাটি পিছনদিকে পুনরাবৃত্তভাবে এমনভাবে কার্যকর করা যায় যদি এটি সম্ভব হয় তবে এটি উপলব্ধি করা ভাল। আমি এই পদ্ধতিটি ব্যবহার করতে যাচ্ছি এবং অ্যাপাচি কমন্স সংগ্রহ থেকে রিভার্সলিস্টআইট্রেটার শ্রেণি ব্যবহার করব।
ডেভিড গ্রুমস

11

আপনি LinkedListসাধারণ ইন্টারফেসের পরিবর্তে কংক্রিট শ্রেণি ব্যবহার করতে পারেন List। তারপরে descendingIteratorবিপরীত দিক দিয়ে পুনরাবৃত্তি করার জন্য আপনার একটি রয়েছে ।

LinkedList<String > linkedList;
for( Iterator<String > it = linkedList.descendingIterator(); it.hasNext(); ) {
    String text = it.next();
}

কেন নেই এর descendingIteratorসাথে নেই ArrayList...


9

এটি একটি পুরানো প্রশ্ন তবে এটিতে জাভা 8-বান্ধব উত্তরের অভাব রয়েছে। স্ট্রিমিং এপিআই-র সহায়তায় তালিকাটি উল্টো-পুনরাবৃত্তি করার কয়েকটি উপায় এখানে রয়েছে:

List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 3, 3, 7, 5));
list.stream().forEach(System.out::println); // 1 3 3 7 5

int size = list.size();

ListIterator<Integer> it = list.listIterator(size);
Stream.generate(it::previous).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

ListIterator<Integer> it2 = list.listIterator(size);
Stream.iterate(it2.previous(), i -> it2.previous()).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList)
IntStream.range(0, size).map(i -> size - i - 1).map(list::get)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList), less efficient due to sorting
IntStream.range(0, size).boxed().sorted(Comparator.reverseOrder())
    .map(list::get).forEach(System.out::println); // 5 7 3 3 1

2
খুব সুন্দর, কেবল একটি অঙ্গরাগ পরিবর্তন: int আকার = list.size (); তালিকার তালিকা <Integer> এটি = list.listIterator (আকার); Stream.generate (এটা :: পূর্ববর্তী) .limit (SIZE) .forEach (System.out :: println);
বেনজ

5

এখানে একটি (স্বাক্ষরিত) বাস্তবায়ন করা হয়েছে ReverseIterable। যখন iterator()বলা হয় এটি একটি বেসরকারী ReverseIteratorবাস্তবায়ন তৈরি করে এবং ফেরত দেয় , যা কেবলমাত্র কলগুলিতে ম্যাপ করা hasNext()হয় hasPrevious()এবং কলগুলি next()ম্যাপ করে previous()। এর অর্থ হল আপনি নীচে ArrayListউল্টোদিকে পুনরাবৃত্তি করতে পারেন :

ArrayList<String> l = ...
for (String s : new ReverseIterable(l)) {
  System.err.println(s);
}

ক্লাস সংজ্ঞা

public class ReverseIterable<T> implements Iterable<T> {
  private static class ReverseIterator<T> implements Iterator {
    private final ListIterator<T> it;

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

    public T next() {
      return it.previous();
    }

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

  private final ArrayList<T> l;

  public ReverseIterable(ArrayList<T> l) {
    this.l = l;
  }

  public Iterator<T> iterator() {
    return new ReverseIterator(l.listIterator(l.size()));
  }
}

আমার কাছে ঠিক দেখাচ্ছে, যদিও পাবলিক কনস্ট্রাক্টরের পরিবর্তে স্থির পদ্ধতি হিসাবে এটি প্রকাশ করা (বেশিরভাগ ক্ষেত্রে) ক্লায়েন্টের জন্য টাইপ প্যারামিটার নির্দিষ্ট করার প্রয়োজন এড়াতে পারে। এইভাবেই পেয়ারা এটি করে ..
কেভিন বোউরিলিয়ন

2
এটি সর্বোত্তম বাস্তবায়ন, তবে ReverseIteratorপ্রয়োজনীয় নির্মাতা নিখোঁজ রয়েছে এবং কোডটির Listপরিবর্তে ব্যবহার করা উচিত ArrayList
অ্যান্ডি

5

তালিকা মোটামুটি ছোট হন, যাতে কর্মক্ষমতা একটি বাস্তব সমস্যা হয় না, ব্যবহার করতে পারেন reverseএর -metod Listsমধ্যে -class Google Guava। ফলনটি বেশ- for-eachকোড করে এবং মূল তালিকাটি একই থাকে। এছাড়াও, বিপরীত তালিকাটি মূল তালিকাকে সমর্থন করে, তাই মূল তালিকার কোনও পরিবর্তন বিপরীত তালিকায় প্রতিফলিত হবে।

import com.google.common.collect.Lists;

[...]

final List<String> myList = Lists.newArrayList("one", "two", "three");
final List<String> myReverseList = Lists.reverse(myList);

System.out.println(myList);
System.out.println(myReverseList);

myList.add("four");

System.out.println(myList);
System.out.println(myReverseList);

নিম্নলিখিত ফলাফল ফলন:

[one, two, three]
[three, two, one]
[one, two, three, four]
[four, three, two, one]

যার অর্থ মাইলিস্টের বিপরীত পুনরাবৃত্তিটি এইভাবে লেখা যেতে পারে:

for (final String someString : Lists.reverse(myList)) {
    //do something
}

5

একটি কাস্টম তৈরি করুন reverseIterable


কেন এটি ভোট নিচে নেমেছে তা জানেন না, আমি সম্ভবত এটির তালিকা তৈরি করতে পারি pper
আল্লায় লালনোদে

এটি কালেকশনস.রেভারস () আইএমএইচওর কল করার চেয়ে কম পরিষ্কার নয়।
অ্যাডামস্কি

@ অ্যালাইন: সম্মত পুনরায়। ডাউনভোটগুলি যদিও আমি দেখতে পাচ্ছি না কেন আপনি তালিকার তালিকায় কল ("list.size ())" "পরিষ্কার না" হিসাবে দেখছেন। এমনকি যদি আপনি এটি আবদ্ধ করেন তবে আপনাকে এখনও কোথাও একই পদ্ধতি কল করতে হবে।
অ্যাডামস্কি

ধরুন না, কেবল পরিচ্ছন্নতার জন্য পারফরম্যান্স হিট নিতে রাজি নন।
আল্লায় লালনোদে

18
আমি এটিকে একটি সম্পূর্ণ উত্তর বিবেচনা করি বলে মনে করি না বলে ভোট দিয়েছেন।
মার্টেন বোদেউয়েস

3

খুব সাধারণ উদাহরণ:

List<String> list = new ArrayList<String>();

list.add("ravi");

list.add("kant");

list.add("soni");

// Iterate to disply : result will be as ---     ravi kant soni

for (String name : list) {
  ...
}

//Now call this method

Collections.reverse(list);

// iterate and print index wise : result will be as ---     soni kant ravi

for (String name : list) {
  ...
}



1

কোডটি দেখতে যা দেখতে দেখতে:

List<Item> items;
...
for (Item item : In.reverse(items))
{
    ...
}

এই কোডটি "ইন.জাভা" নামক কোনও ফাইলে রাখুন:

import java.util.*;

public enum In {;
    public static final <T> Iterable<T> reverse(final List<T> list) {
        return new ListReverseIterable<T>(list);
    }

    class ListReverseIterable<T> implements Iterable<T> {
        private final List<T> mList;

        public ListReverseIterable(final List<T> list) {
            mList = list;
        }

        public Iterator<T> iterator() {
            return new Iterator<T>() {
                final ListIterator<T> it = mList.listIterator(mList.size());

                public boolean hasNext() {
                    return it.hasPrevious();
                }
                public T next() {
                    return it.previous();
                }
                public void remove() {
                    it.remove();
                }
            };
        }
    }
}

1
এটি থ্রেডে অন্য কোথাও উল্লেখ করা হয়েছে, তবে listIteratorক্ষেত্রটি Iteratorবাস্তবায়নের নয়, Iterableবাস্তবায়নের অভ্যন্তরে থাকা দরকার।
অ্যান্ডি

1
ক্লাস নয়, এনাম টাইপ ব্যবহার করছেন কেন?
Aubin,

1
এটি একটি ব্যক্তিগত ডিফল্ট কনস্ট্রাক্টর না লিখেই 'ইন' ক্লাসটিকে অ-তাত্ক্ষণিক করে তোলে। ক্লাসগুলির জন্য ভাল যেখানে কেবল স্থির পদ্ধতি রয়েছে have
ইন্ট্রিপিডিস

আমি বলব যে প্রাইভেট ডিফল্ট কনস্ট্রাক্টর লেখা এড়ানোর জন্য এনামগুলিকে গালি দেওয়া মোটেও বিভ্রান্তিকর। Enums এবং ক্লাসের জন্য ক্লাসের জন্য enums সম্পর্কে কীভাবে? এনামে ক্লাস তৈরি করে এটি স্পষ্টভাবে একটি name()পদ্ধতি, একটি ordinal()পদ্ধতি এবং একটি static valueOf()পদ্ধতিও পায়, উদাহরণস্বরূপ।
জেএইচএইচ

1
হ্যাঁ আপনি আপনার মতামত দিয়ে চালিয়ে যেতে পারেন এবং এটি খুব ভাল কাজ করবে, তবে আমি তার বিপরীতে ভাবি। ক্লাসগুলি অবজেক্টগুলিকে তাত্ক্ষণিকভাবে চালিত করার জন্য এবং কোনও প্রাইভেট ডিফল্ট কনস্ট্রাক্টরকে তাদের ইনস্ট্যান্টেশন বাধা দেওয়ার জন্য অন্তর্ভুক্ত করে গালি দেওয়ার জন্য সর্বোত্তমভাবে বিভ্রান্ত হয়। জাভাতে, এনামগুলি আসলে ক্লাস হয় তবে সেগুলি কখনই ডিজাইনের মাধ্যমে ইনস্ট্যান্ট করা যায় না।
ইন্ট্রিপিডিস

0

হিসাবে অন্তত বলা হয়েছে দুইবার, আপনি ব্যবহার করতে পারেন descendingIteratorএকটি সঙ্গে Dequeএকটি সঙ্গে বিশেষ করে, LinkedList। আপনি যদি প্রতিটি লুপ ব্যবহার করতে চান (অর্থাত্ একটি আছে Iterable), আপনি এটির মতো একটি মোড়ক তৈরি এবং ব্যবহার করতে পারেন:

import java.util.*;

public class Main {

    public static class ReverseIterating<T> implements Iterable<T> {
        private final LinkedList<T> list;

        public ReverseIterating(LinkedList<T> list) {
            this.list = list;
        }

        @Override
        public Iterator<T> iterator() {
            return list.descendingIterator();
        }
    }

    public static void main(String... args) {
        LinkedList<String> list = new LinkedList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");

        for (String s : new ReverseIterating<String>(list)) {
            System.out.println(s);
        }
    }
}

-10

কারণ: "অ্যারেলিস্টের সাথে কেন কোন উতরাইয়ের ব্যবস্থা নেই ... জানেন না"

যেহেতু অ্যারে তালিকা তালিকায় ডেটা যুক্ত করা হয় ঠিক একই ক্রমে তালিকাকে রাখে না। সুতরাং, অ্যারেলিস্ট কখনই ব্যবহার করবেন না।

লিঙ্কযুক্ত তালিকাগুলি এডিডিকে একই ক্রমে ডাটা রাখবে।

সুতরাং, উপরে আমার উদাহরণে, আমি ব্যবহারকারীকে তাদের মন মোচড়ানোর জন্য এবং তাদের দিক থেকে কিছুটা ওয়ার্কআউট করার জন্য অ্যারেলিস্ট () ব্যবহার করেছি।

এর পরিবর্তে

List<String> list = new ArrayList<String>();

ব্যবহার:

List<String> list = new LinkedList<String>();

list.add("ravi");

list.add("kant");

list.add("soni");

// Iterate to disply : result will be as ---     ravi kant soni

for (String name : list) {
  ...
}

//Now call this method

Collections.reverse(list);

// iterate and print index wise : result will be as ---     soni kant ravi

for (String name : list) {
  ...
}

4
"যেহেতু অ্যারে তালিকা তালিকায় ডাটা যুক্ত করা হয়েছে ঠিক একই ক্রমে সেই তালিকাটি রাখে না" উম্ম, হ্যাঁ এটি করে, অন্তত এটি লিঙ্কযুক্ত তালিকার মতো একই পদ্ধতিতে কাজ করে। তারা কীভাবে তা উদাহরণ দেয় না?
কর্সিকা

হ্যাঁ, অ্যারেলিস্ট এবং লিংকডলিস্ট (সাধারণভাবে তালিকার চুক্তি) আইটেমগুলি সারণিতে রাখুন। সেট চুক্তিটি অর্ডারড বা সাজানো (ট্রিটসেট) দ্বারা অর্ডার করা হয়। বিপরীত ধারণাটি খারাপ নয় তবে মনে রাখবেন যে এটি আসলে তালিকাটিকে পুনরায় সাজায় যা ধীর হতে পারে।
বিল কে

2
আমি এই উত্তরটিকে অগ্রাহ্য করেছি কারণ এটি ভ্রান্তভাবে জানিয়েছে যে অ্যারেলিস্টগুলি আইটেমগুলি সন্নিবেশ ক্রমে রাখে না। @ বিল-কে নোট হিসাবে, সমস্ত তালিকাকে সংজ্ঞা অনুসারে সংগ্রহের আদেশ দেওয়া হয়। পরিবর্তে একটি লিংকডলিস্ট ব্যবহার করার পরামর্শটির যোগ্যতা রয়েছে, কারণ এটি অবতরণকারী () পদ্ধতির বৈশিষ্ট্যযুক্ত, তবে কেবল যদি পারফরম্যান্স মেমরি এবং বিমূর্তির চেয়ে বড় উদ্বেগ হয়।
মাইকেল শ্যাপার 0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.