Sometimes we meet a situation where we should iterate (or map) over a collection, applying the same procedure (function) for all elements except the first one. The simplest example is finding the max element of collection, but is not a good one: the operation here is idempotent. More realistic example is table dumping by portions: at first request we create a file with header for columns, then populate it.

What is the common approach (or most idiomatic way) to implementation of this pattern? I'm interested in both imperative and functional programming paradigms.

A few variants of possible implementations (c-like pseudocode):

first (imperative)

funcFirst(collection[0]); //duplicate code if funcFirst is something1 + func() + something2
for (int i = 1; i < collection.size(); i++){
    func(collection[i]);
}

second (imperative)

for (int i = 0; i < collection.size(); i++){
    if (i == 0) //too many extra checks
        funcFirst(collection[0]);
    else 
        func(collection[i]); 
}

third (imperative)

for (int i = 0; i < collection.size(); i++){
    if (i == 0) //too many extra checks
        initSomenthing(collection[0]); //double read of collection[0]
    func(collection[i]); 
}

first (functional)

funcFirst(collection.first()) //duplicate code if funcFirst is something1 + func() + something2
collection.drop(1).map( func )

second (functional)

collection.iterateWithIndex.map (if index == 0 funcFirst else func) 

third (functional)

collection.fold (init(collection.first), func) //double read of collection[0]
有帮助吗?

解决方案

I would try something like that in Scala for mapping differently the first element :

def apply[T,X](f: T=>X, g: T=>X, l: Seq[T]): Seq[X] = l match {
   case Nil => Nil
   case head :: tail => f(head) +: apply(g,g,tail)
}

> apply((x: Int)=> x*x, (x: Int)=> -x, List(5,4,3,2,1))
res1: Seq[Int] = List(25, -4, -3, -2, -1)

The idea is to do nothing if the list is empty. Otherwise, one replaces the head of the list by a function of this head: head becomes f(head), and the rest of the list is mapped by using an other function g, whatever the element is on the head of the tail of the list.

As @jk noted, the recursive call to apply could be replaced by a map. However, my approach is a little bit more flexible (it was not required for answering the original question), since one can alternate the functions to apply (f for odd elements, g for even elements, for instance), or one can decide which function should be applied on the next element (if any) depending on an arbitrary predicate on the current element.

其他提示

Just split the list into a scalar value to process separately, then work on the rest.

val first = list.head
val rest = list.tail
val firstResult = firstFunc(first)
val restResult = rest.map(restFunc)
许可以下: CC-BY-SA归因
scroll top