summaryrefslogtreecommitdiff
path: root/src/library/scala/Iterable.scala
blob: 933d597b83fa8a0c08b0b48d7c81d3bf652d159e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2006, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id$


package scala;

import Predef.error;

object Iterable {
  implicit def view[A <% Ordered[A]](x: Iterable[A]): Ordered[Iterable[A]] =
    new Ordered[Iterable[A]] {
      def compare[B >: Iterable[A] <% Ordered[B]](that: B): Int = that match {
        case y: Iterable[A] =>
          val xs = x.elements;
	  val ys = y.elements;
	  var res = 0;
	  while (xs.hasNext && ys.hasNext && (res == 0)) {
            res = xs.next compare ys.next;
          }
	  if (xs.hasNext) 1
	  else if (ys.hasNext) -1
          else res;
        case _ =>
          -(that compare x)
      }
    }

  /** The minimum element of a non-empty sequence of ordered elements */
  def min[A <% Ordered[A]](seq: Iterable[A]): A = {
    val xs = seq.elements;
    if (!xs.hasNext) error("min(<empty>)");
    var min = xs.next;
    while (xs.hasNext) {
      val x = xs.next;
      if (x < min) min = x;
    }
    min
  }

  /** The maximum element of a non-empty sequence of ordered elements */
  def max[A <% Ordered[A]](seq: Iterable[A]): A = {
    val xs = seq.elements;
    if (!xs.hasNext) error("max(<empty>)");
    var max = xs.next;
    while (xs.hasNext) {
      val x = xs.next;
      if (max < x) max = x;
    }
    max
  }
}


/** Collection classes mixing in this class provide a method
 *  <code>elements</code> which returns an iterator over all the
 *  elements contained in the collection.
 *
 *  @author  Matthias Zenger
 *  @version 1.1, 04/02/2004
 */
trait Iterable[+A] {

    /** Creates a new iterator over all elements contained in this
     *  object.
     *
     *  @return the new iterator
     */
    def elements: Iterator[A];

    /** Concatenates two iterable objects
     *
     *  @return the new iterable object
     *  @author buraq
     */
    def concat[B >: A](that:Iterable[B]): Iterable[B] = new Iterable[B] {
      def elements: Iterator[B] = Iterable.this.elements.append(that.elements);
    }

    /** Apply a function <code>f</code> to all elements of this
     *  iterable object.
     *
     *  @param  f   a function that is applied to every element.
     */
    def foreach(f: A => Unit): Unit = elements.foreach(f);

    /** Apply a predicate <code>p</code> to all elements of this
     *  iterable object and return true, iff the predicate yields
     *  true for all elements.
     *
     *  @param   p     the predicate
     *  @returns true, iff the predicate yields true for all elements.
     */
    def forall(p: A => Boolean): Boolean = elements.forall(p);

    /** Apply a predicate <code>p</code> to all elements of this
     *  iterable object and return true, iff there is at least one
     *  element for which <code>p</code> yields true.
     *
     *  @param   p     the predicate
     *  @returns true, iff the predicate yields true for at least one element.
     */
    def exists(p: A => Boolean): Boolean = elements.exists(p);

    /** Find and return the first element of the iterable object satisfying a
     *  predicate, if any.
     *
     *  @param p the predicate
     *  @return the first element in the iterable object satisfying <code>p</code>,
     *  or <code>None</code> if none exists.
     */
    def find(p: A => Boolean): Option[A] = elements.find(p);

    /** Combines the elements of this list together using the binary
     *  operator <code>op</code>, from left to right, and starting with
     *  the value <code>z</code>.
     *  @return <code>op(... (op(op(z,a0),a1) ...), an)</code> if the list
     *  is <code>List(a0, a1, ..., an)</code>.
     */
    def foldLeft[B](z: B)(op: (B, A) => B): B = elements.foldLeft(z)(op);

    /** Combines the elements of this list together using the binary
     *  operator <code>op</code>, from rigth to left, and starting with
     *  the value <code>z</code>.
     *  @return <code>a0 op (... op (an op z)...)</code> if the list
     *  is <code>[a0, a1, ..., an]</code>.
     */
    def foldRight[B](z: B)(op: (A, B) => B): B = elements.foldRight(z)(op);

    /** Similar to <code>foldLeft</code> but can be used as
     *  an operator with the order of list and zero arguments reversed.
     *  That is, <code>z /: xs</code> is the same as <code>xs foldLeft z</code>
     */
    def /:[B](z: B)(f: (B, A) => B): B = foldLeft(z)(f);

    /** An alias for <code>foldRight</code>.
     *  That is, <code>xs :\ z</code> is the same as <code>xs foldRight z</code>
     */
    def :\[B](z: B)(f: (A, B) => B): B = foldRight(z)(f);

    /** Checks if the other iterable object contains the same elements.
     *
     *  @param that  the other iterable object
     *  @return true, iff both iterable objects contain the same elements.
     */
    def sameElements[B >: A](that: Iterable[B]): Boolean = {
        val ita = this.elements;
        val itb = that.elements;
        var res = true;
        while (res && ita.hasNext && itb.hasNext) {
            res = (ita.next == itb.next);
        }
        !ita.hasNext && !itb.hasNext && res
    }
}