F # - разбить список на конкатенацию строк через интервал - PullRequest
1 голос
/ 14 января 2009

У меня есть список адресов электронной почты, и мне нужно отправить уведомление по электронной почте на каждый адрес. Я хотел бы сделать это в блоках по 25 адресов одновременно. Есть ли какой-нибудь быстрый способ на функциональном языке, таком как F #, «сложить» (объединить) 25 адресов электронной почты вместе ... каждый разделенный точкой с запятой. Я знаю, что в .NET есть метод String.Split, но мне нужно объединить 25 одновременно.

Какой самый элегантный способ выполнить это в F #?

Ответы [ 4 ]

1 голос
/ 28 июня 2011

Если это все еще актуально, здесь есть функция для соединения последовательности строк с использованием разделителя, но без преобразования в массив.

open System
open System.Text

/// Join a sequence of strings using a delimiter.
/// Equivalent to String.Join() but without arrays.
let join (items : seq<string>) (delim : string) =
    // Collect the result in the string builder buffer
    // The end-sequence will be "item1,delim,...itemN,delim"
    let buff = 
        Seq.fold 
            (fun (buff :StringBuilder) (s:string) -> buff.Append(s).Append(delim)) 
            (new StringBuilder()) 
            items

    // We don't want the last delim in the result buffer, remove
    buff.Remove(buff.Length-delim.Length, delim.Length).ToString()
1 голос
/ 14 января 2009

Вот способ разбить на группы не более N:

// break a sequence up into a sequence of arrays, 
// each of length at most 'n'
let Break n (s:seq<_>) =
    seq {
        use e = s.GetEnumerator()
        while e.MoveNext() do
            let i = ref 0
            yield [|
                yield e.Current
                i := !i + 1
                while !i < n && e.MoveNext() do            
                    yield e.Current
                    i := !i + 1 |] }

и тогда ваше решение будет просто похоже на

let Sendmail addr = printf "%A\n\n" addr
let allMails = [for i in 1..25 -> sprintf "a%i@example.com" i]
allMails 
|> Break 5
|> Seq.map (fun arr -> System.String.Join(";", arr))
|> Seq.iter Sendmail
0 голосов
/ 15 января 2009

Модуль Seq имеет оконную функцию, но это дает вам скользящее окно, поэтому этот вопрос не годится.

Вот моя версия, я не тестировал сравнение производительности с другими ответами, но она красивее (я думаю!)

//Add an "extension function" to the Seq module
module Seq = 
    let rec chunks n (s:#seq<_>) =
        seq {
                 if Seq.length s <= n then
                    yield s
                 else
                    yield Seq.take n s
                    yield! chunks n (Seq.skip n s)           
            }

//Make curried version of String.Join
let join sep (s:#seq<string>) = System.String.Join(sep, Array.of_seq s)

//Compose the bits together
let mailMerge n = Seq.chunks n >> Seq.map (join ";")

//Test
mailList |> mailMerge 25

Возможно, вы также можете посмотреть Массив срезов .

0 голосов
/ 14 января 2009

Это не слишком красиво, но это работает:

let breakWords separator groupSize (input : string) =
    let words = input.Split([| separator |])
    let arraySize = words.Length / groupSize + (if words.Length % groupSize > 0 then 1 else 0)
    let groups = Array.init arraySize (fun index ->
        let startIndex = index * groupSize
        let endIndex = Math.Min(startIndex + groupSize - 1, words.Length - 1)
        words.[startIndex .. endIndex])
    groups |> Seq.map (fun x -> String.Join(";", x))
...