2010-07-12 30 views
5

Tôi có một iterator của dòng từ một tập tin rất lớn cần phải được đặt trong nhóm khi tôi di chuyển cùng. Tôi biết nơi mỗi nhóm kết thúc bởi vì có một giá trị sentinel trên dòng cuối cùng của mỗi nhóm. Vì vậy, về cơ bản tôi muốn viết một hàm nhận một biến lặp và một giá trị sentinel, và trả về một iterator của các nhóm được kết thúc bởi giá trị sentinel. Một cái gì đó như:nhóm các mục trong một iterable bằng cách tìm kiếm một giá trị sentinel (trong scala)

scala> groups("abc.defg.hi.jklmn.".iterator, '.') 
res1: Iterator[Seq[Char]] = non-empty iterator 

scala> groups("abc.defg.hi.jklmn.".iterator, '.').toList 
res19: List[Seq[Char]] = List(List(a, b, c, .), List(d, e, f, g, .), List(h, i, .), List(j, k, l, m, n, .)) 

Lưu ý rằng tôi muốn các mục được gửi kèm vào cuối mỗi nhóm. Đây là giải pháp hiện tại của tôi:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {     
    def hasNext = iter.hasNext 
    def next = iter.takeWhile(_ != sentinel).toList ++ List(sentinel) 
} 

Tôi nghĩ rằng điều này sẽ hiệu quả, nhưng tôi đoán là tốt, nhưng phải thêm lại mã thông báo mỗi lần cho tôi một chút mã. Có cách nào tốt hơn để làm điều này?

+0

Bạn có muốn một người được gửi đến nhóm cuối cùng nếu nó không chứa nó không? (ví dụ: "abc.def" -> ["abc.", "def."]) –

+0

Lý tưởng nhất là không, mặc dù thực tế tôi nghĩ điều đó không quan trọng. – Steve

+0

Nó xảy ra mà tôi đã muốn, và yêu cầu, một 'takeTo' (cộng' dropTo' và 'spanTo'), sẽ hoạt động giống như' takeWhile', nhưng trả về một phần tử nữa - phần tử đầu tiên mà vị ngữ là đúng. Nếu bạn cảm thấy như tôi, bạn có thể thả một lưu ý ở đây: https://lampsvn.epfl.ch/trac/scala/ticket/2963 –

Trả lời

2

Xấu xí, nhưng nên được nhiều hoạt động tốt hơn giải pháp của bạn:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {     
    def hasNext = iter.hasNext 
    def next = iter.takeWhile{ 
     var last = null.asInstanceOf[T] 
     c => { val temp = last; last = c; temp != sentinel} 
    }.toList 
    } 
+0

Wow, đó là xấu xí, nhưng mát mẻ. =) Bạn có thể di chuyển "var last" ra một biến riêng, và sau đó nó có vẻ ít xấu xí hơn một chút. – Steve

5

Ít đọc hơn của bạn, nhưng nhiều hơn "đúng" khi nhóm chính thức không có một giá trị chấm dứt sentinel:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { 
def hasNext = iter.hasNext 
def next: Seq[T] = { 
    val builder = scala.collection.mutable.ListBuffer[T]() 
    while (iter.hasNext) { 
     val x = iter.next 
     builder.append(x) 
     if (x == sentinel) return builder 
    } 
    builder 
} 
} 

Hoặc, đệ quy:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { 
    def hasNext = iter.hasNext 
    def next: Seq[T] = { 
     @scala.annotation.tailrec 
     def build(accumulator: ListBuffer[T]): Seq[T] = { 
     val v = iter.next 
     accumulator.append(v) 
     if (v == sentinel || !iter.hasNext) => accumulator 
     else build(accumulator) 
     } 
     build(new ListBuffer[T]()) 
    } 
    } 
Các vấn đề liên quan