Как изящно объединить два кортежа с указанным ключом? - PullRequest
0 голосов
/ 16 января 2019

Я написал код, но выглядит ужасно.
Изображение есть две последовательности, такие как:

let x = [(1,"x");(2,"y")]
let y = [(1, "xx", "xxx");(2,"yy","yyy")]  

Элементы являются кортежами, но не одинаковой формы.
Результат должен быть [(1, "x", "xx", "xxx");(2, "y", "yy", "yyy")].
Первый элемент в кортеже - это ключ.

Код, который я написал, использовал карту как:

let x = [(1,"x");(2,"y")]
let y = [(1, "xx", "xxx");(2,"yy","yyy")]  
let mapY = y |> Seq.map (fun (a,b,c) -> (a, (b, c))) |> Map.ofSeq

let r = [
    for (k,v) in x do
        let (v1,v2) = mapY |> Map.tryFind k |> Option.orElse (Some ("","")) |> Option.get
        yield (k, v, v1, v2)
]

printfn "%A" r

не так грациозно.
Поэтому мне интересно какое-нибудь лучшее решение? (Элемент кортежа в вопросе может иметь тип seq, например, кортеж).
Ключевой вопрос заключается в том, как изящно объединить две последовательности по ключу.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Я согласен, что использование join, как показано @torbonde, вероятно, самый хороший способ сделать это.

Если вы предпочитаете придерживаться базовых List функций, то я думаю, что то, что у вас есть, вероятно, настолько хорошо, насколько это возможно. Один незначительный твик должен заменить orElse на defaultValue:

let (v1,v2) = mapY |> Map.tryFind k |> Option.defaultValue ("","")

Еще одна вещь, которую я хотел бы рассмотреть: нужны ли вам плоские кортежи - если бы вы были довольны вложением кортежей как на входной, так и на выходной сторонах, вы могли бы сделать что-то подобное (что по сути все еще является вашим исходным кодом, немного короче):

let x = [(1,"x");(2,"y")]
let y = [(1, ("xx", "xxx"));(2,("yy","yyy"))]  

let mapY = Map.ofSeq y
let r = x |> List.map (fun (k, v) -> 
     k, v, defaultArg (mapY.TryFind k) ("",""))
0 голосов
/ 16 января 2019

Я бы предложил использовать вычислительное выражение query (см. здесь для получения дополнительной информации и примеров). В вашем случае решение будет выглядеть так:

let r =
    query {
        for (k1, v) in x do
        join (k2, v1, v2) in y on (k1 = k2)
        select(k1, v, v1, v2) }
    |> Seq.toList

Обратите внимание, что оператор join, используемый здесь, на самом деле является внутренним соединением. Существует много других методов соединения (а также других операторов), перечисленных на странице, указанной выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...