F # Three Arrays - Заменить уникальные значения в оригинальном массиве новыми значениями - PullRequest
0 голосов
/ 09 мая 2018

У меня есть три массива - первый, второй и третий. второй содержит уникальные значения первого, а третий содержит новые значения для замены в первом путем сопоставления со вторым следующим образом:

module SOQN = 

   open System

   let first  = [|"A"; "B"; "C"; "A"; "B"; "A"; "C"; "B"; "C"; "C"; "C"|]
   let second = [|"A"; "B"; "C"|]
   let third  = [|"1"; "2"; "3"|]

   let rplc (x:string[]) (y:string[]) (z:string[]) = 
      first
      // |> Array.map (fun w -> Array.iter2 (fun x y -> (if w = x then y)) second third)

   let fourth = 
      rplc first second third

   printfn ""
   printfn "fourth: %A" fourth

   // Expected Result: fourth: [|"1"; "2"; "3"; "1"; "2"; "1"; "3"; "2"; "3"; "3"; "3"|]
   // Actual Result:   fourth: [|"A"; "B"; "C"; "A"; "B"; "A"; "C"; "B"; "C"; "C"; "C"|]

Моя строка комментариев не работает, но я не знаю, почему?

1 Ответ

0 голосов
/ 09 мая 2018

Самый простой способ - создать таблицу подстановок из второго и третьего массивов, затем сопоставить каждый элемент первого массива и использовать ее в качестве ключа.

let first  = [|"A"; "B"; "C"; "A"; "B"; "A"; "C"; "B"; "C"; "C"; "C"|]
let second = [|"A"; "B"; "C"|]
let third  = [|"1"; "2"; "3"|]

let lookupTbl = Map(Array.zip second third) //create a Map/Dictionary from the zipped values

first
|> Array.map (fun x -> lookupTbl.[x]) //Use the first array's values as keys
//val it : string [] = [|"1"; "2"; "3"; "1"; "2"; "1"; "3"; "2"; "3"; "3"; "3"|]

Вы также можете использовать TryFind, если не уверены, что все ключи существуют, но в вашем случае это не кажется необходимым.

Ваш первоначальный случай не работает, потому что вы пытаетесь использовать if в качестве оператора, поэтому он возвращает unit (потому что, если x не равен w).

Если вы хотите остаться ближе к своей исходной структуре, вы можете использовать сопоставление с шаблоном вместо if, а затем удалить несоответствия. Array.collect сворачивает массив массивов в один массив. Выражение match делает то же, что и if в вашем коде, но оно возвращает значение Some, если есть совпадение, и None в противном случае. Наконец, мы избавляемся от оболочек None и Some Option с помощью Array.choose.

let rplc (x:string[]) (y:string[]) (z:string[]) = 
  first
  |> Array.collect (fun w -> 
                        Array.map2 (fun x y -> 
                                                match (w = x) with
                                                | true -> Some(y)
                                                | _ -> None ) second third)
  |> Array.choose id

let fourth = 
  rplc first second third

printfn ""
printfn "fourth: %A" fourth

// val fourth : string [] =
//   [|"1"; "2"; "3"; "1"; "2"; "1"; "3"; "2"; "3"; "3"; "3"|]
// val it : unit = ()
...