Identifying last loop when using for each

后端 未结 25 1393
眼角桃花
眼角桃花 2020-12-08 09:59

I want to do something different with the last loop iteration when performing \'foreach\' on an object. I\'m using Ruby but the same goes for C#, Java etc.

          


        
相关标签:
25条回答
  • 2020-12-08 10:15

    I don't know how for-each loops works in other languages but java. In java for-each uses the Iterable interface that is used by the for-each to get an Iterator and loop with it. Iterator has a method hasNext that you could use if you could see the iterator within the loop. You can actually do the trick by enclosing an already obtained Iterator in an Iterable object so the for loop got what it needs and you can get a hasNext method inside the loop.

    List<X> list = ...
    
    final Iterator<X> it = list.iterator();
    Iterable<X> itw = new Iterable<X>(){
      public Iterator<X> iterator () {
        return it;
      }
    }
    
    for (X x: itw) {
      doSomething(x);
      if (!it.hasNext()) {
        doSomethingElse(x);
      }
    }
    

    You can create a class that wraps all this iterable and iterator stuff so the code looks like this:

    IterableIterator<X> itt = new IterableIterator<X>(list);
    for (X x: itit) {
      doSomething(x);
      if (!itit.hasNext()) {
        doSomethingElse(x);
      }
    }
    
    0 讨论(0)
  • 2020-12-08 10:16

    I think I prefer kgiannakakis's solution, however you could always do something like this;

    list = ['A','B','C']
    list.each { |i|
       if (i != list.last)
          puts "Looping:#{i}"
       else
          puts "Last one:#{i}"
       end
    }
    
    0 讨论(0)
  • 2020-12-08 10:16

    Would it be a viable solution for your case to just take the first/last elements out of your array before doing the "general" each run?

    Like this:

    list = ['A','B','C','D']
    first = list.shift
    last = list.pop
    
    puts "First one: #{first}"
    list.each{|i|
      puts "Looping: "+i
    }
    puts "Last one: #{last}"
    
    0 讨论(0)
  • 2020-12-08 10:17

    You can define an eachwithlast method in your class to do the same as each on all elements but the last, but something else for the last:

    class MyColl
      def eachwithlast
        for i in 0...(size-1)
          yield(self[i], false)
        end
        yield(self[size-1], true)
      end
    end
    

    Then you could call it like this (foo being an instance of MyColl or a subclass thereof):

    foo.eachwithlast do |value, last|
      if last
        puts "Last one: "+value
      else
        puts "Looping: "+value
      end
    end
    

    Edit: Following molf's suggestion:

    class MyColl
      def eachwithlast (defaultAction, lastAction)
        for i in 0...(size-1)
          defaultAction.call(self[i])
        end
        lastAction.call(self[size-1])
      end
    end
    
    foo.eachwithlast(
        lambda { |x| puts "looping "+x },
        lambda { |x| puts "last "+x } )
    
    0 讨论(0)
  • 2020-12-08 10:18

    You could do something like that (C#) :

    string previous = null;
    foreach(string item in list)
    {
        if (previous != null)
            Console.WriteLine("Looping : {0}", previous);
        previous = item;
    }
    if (previous != null)
        Console.WriteLine("Last one : {0}", previous);
    
    0 讨论(0)
  • 2020-12-08 10:19

    This problem can be solved in an elegant way using pattern matching in a functional programming language such as F#:

    let rec printList (ls:string list) = 
        match ls with
            | [last] -> "Last " + last
            | head::rest -> "Looping " + head + "\n" + printList (rest)
            | [] -> ""
    
    0 讨论(0)
提交回复
热议问题