【问题标题】:F# Conversion from tuple to enumerated listF#从元组到枚举列表的转换
【发布时间】:2013-01-21 23:32:44
【问题描述】:

下面的代码源于欧几里德距离算法的工作。颜色表只是测试算法的工具。它可能是在重新发明轮子,但它本身很有用。任何 3 个 RGB 整数 (0-255) 都可以与最接近的 X11 颜色名称相关联。非常感谢 svick 的见解。

在当前代码中,ColorTable 在实例创建后通过 AddColor 方法进行初始化。但是,可以使用 loadrgb/colorinfo 组合从 Web 上拉下 X11 颜色表。

我在从 X11 rgb.txt 文件的在线版本初始化颜色表时遇到了最后一个问题。我需要将文本解析为 {Name: Values:} 列表。目前,结果在字符串元组中。我正在努力让“colorinfo”加载“ColorTable”。

// currently the color table is create via the AddColor method, however
// the initial values should be created with the loadrgb and colorinfo members
type MyFSColorTable() = 

// pull the X11 rgb.txt color table off the web in text format
  static let loadrgb =
    let url = "http://people.csail.mit.edu/jaffer/Color/rgb.txt"
    let req = WebRequest.Create(url)
    let resp = req.GetResponse()
    let stream = resp.GetResponseStream()
    let reader = new StreamReader(stream)
    let txt = reader.ReadToEnd()
    txt

// parse the text of the rgb.txt color table into a Name: Values: list
  static let colorinfo =
      loadrgb.Split([|'\n'|])
      |> Seq.skip 1
      |> Seq.map (fun line -> line.Split([|'\t'|]))        
      |> Seq.filter (fun values -> values |> Seq.length = 3)
      |> Seq.map (fun values -> string values.[0], string values.[2])
      |> Seq.map (fun (rgb, name) -> rgb.Split([|' '|]), name)
      |> Seq.map (fun (rgb, name) -> [|name, rgb.[0], rgb.[1], rgb.[2]|])

  // Mutable Color Table will be defined on-the-fly
  let mutable ColorTable = []
  // Euclidean distance between 2 vectors - float is overkill here
  static let Dist (V1: float[]) V2 =
    Array.zip V1 V2
      |> Array.map (fun (v1, v2) -> pown (v1 - v2) 2)
      |> Array.sum

//    Add new colors to the head of the ColorTable
  member x.AddColor name rgb = ColorTable <- {Name = name; Values = rgb}::ColorTable

//    Find nearest color by calculating euclidean distance of all colors, 
//    then calling List.minBy for the smallest 
  member x.FindNearestColor (rgb : float[]) =
    let nearestColor =
      ColorTable |> List.minBy (fun color -> Dist rgb color.Values)
    nearestColor.Name

【问题讨论】:

    标签: algorithm list f# type-conversion tuples


    【解决方案1】:

    目前,您构造 colorinfo 的代码会生成一个序列,其中包含一个数组,该数组只有一个元素,该元素是一个元组(包含四个字符串)。这意味着总体结果的类型是-在您当前的版本中-seq&lt;(string * string * string * string) []&gt;

      (...)
      |> Seq.map (fun (rgb, name) -> 
           [|name, rgb.[0], rgb.[1], rgb.[2] |]
    

    这可能不是有意的——如果你想创建一个包含四个字符串的数组,你需要使用分号而不是逗号[| name; rgb.[0]; ... |],如果你想创建四元素元组,那么你可以省略@987654325 @ 和 |] 在元组周围。

    没有办法自动将数组或元组转换为命名记录类型(假设您有一个带有Name:stringValues:float[] 的记录),因此最好的选择是在您的最后一步中进行此转换管道。您可以将以上内容替换为:

      |> Seq.map (fun (rgb, name) -> 
            { Name = name
              Values = [| float rgb.[0]; float rgb.[1]; float rgb.[2] |] })
      |> List.ofSeq
    

    我还在 sn-p 的末尾添加了List.ofSeq,以便您返回一个列表 - 这与您目前用于 ColorTable 的类型相同。

    (或者,您可以说Values = Array.map float rgb,它将rgb 中的所有字符串转换为浮点数并适用于任何长度的数组。)

    【讨论】:

      【解决方案2】:

      您可以缩短您的代码,并根据需要返回{Name: string; Values: float[]} list,使用以下内容:

      static let colorinfo =
        loadrgb.Split('\n')
          |> Seq.skip 1
          |> Seq.choose (fun line ->
            match line.Split('\t') with
            | [|rgb; _; name|] ->
              let values = rgb.Split(' ') |> Array.map float
              Some({Name=name; Values=values})
            | _ -> None)
          |> Seq.toList
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-17
        • 2011-08-02
        • 2013-06-11
        • 1970-01-01
        • 2020-05-04
        相关资源
        最近更新 更多