在Array中搜索2个值,彼此相邻

时间:2017-08-02 07:53:12

标签: f# functional-programming

我正在解决我在C#中解决的问题,但现在我将我的代码移植到F#。我有一个字节数组,我需要在这个数组中搜索两个值(x,y)。当我找到x时,需要检查:如果y在下一个索引上,我们就匹配了。如果y不在下一个索引上,则搜索将继续。我该如何解决这个问题?我尝试使用Array.findIndex,但没有成功,因为当y不在下一个索引时,我不知道如何继续搜索。

编辑:

public void GetValue(byte[] data)
        {
            byte[] temp = new byte[4];
            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] == Adress[0] && data[i + 1] == Adress[1])
                {
                    for (int j = 0; j < temp.Length; j++)
                    {
                        temp[j] = data[j + i + 2];
                    }
                    Value = BitConverter.ToInt32(temp, 0) * 0.01;
                    break;
                }

            }

3 个答案:

答案 0 :(得分:9)

您可以轻松地将其变为功能:

let bytes = [| 104uy; 101uy; 108uy; 108uy; 111uy |]

bytes 
|> Array.pairwise
|> Array.findIndex (fun x -> fst x = snd x)
//2

答案 1 :(得分:3)

你已经接受了你的答案,但我对你的评论感到震惊“我很惊讶在功能编程中可以提供干净的解决方案”。

您也可以在功能上编写C#代码:

var index = Enumerable.Range(0, Int32.MaxValue)
                      .Zip(bytes.Zip(bytes.Skip(1)))
                      .Where(triplet => triplet.Item2.Item1 == triplet.Item2.Item2)
                      .Select(triplet => triplet.Item1)
                      .DefaultIfEmpty(-1)
                      .First();

如果你更进一步,你可以为IEnumerable<T>创建一些扩展方法:

public static class EnumerableExt
{
    public static IEnumerable<Tuple<A, A>> Pairwise<A>(this IEnumerable<A> self) =>
        self.Zip(self.Skip(1));

    public static int IndexOf<A>(this IEnumerable<A> self, Func<A, bool> f) =>
        Enumerable.Range(0, Int32.MaxValue)
                  .Zip(self)
                  .Where(x => f(x.Item2))
                  .Select(x => x.Item1)
                  .DefaultIfEmpty(-1)
                  .FirstOrDefault();

}

然后,它将为您提供与您接受的F#版本几乎完全相同的代码:

var index = bytes.Pairwise()
                 .IndexOf(x => x.Item1 == x.Item2);

C#本身就是一种非常强大的功能语言。如果你有混合C#和F#的项目,并且你希望你的C#看起来和你的F一样好,那么你可能想尝试my functional base class library for C#

答案 2 :(得分:1)

您的C#代码可以按如下方式转换为F#(更好的索引检查,因此您不会遍历数据数组的边界):

let getValue (a : _ []) (d : _ []) =
    let rec aux i =
        if i > data.Length - 6 then nan
        elif d.[i] = a.[0] && d.[i + 1] = a.[1] then
            0.01 * float (System.BitConverter.ToInt32 (d, i + 2))
        else aux (i + 1)
    aux 0

let value = getValue address data

但是,与手动递归循环相比,重用库函数可以使代码更容易读取,我们也可以按照建议使用Array.pairwise

let getValue2 (a : byte []) d =
    d |> Array.pairwise
      |> Array.tryFindIndex (fun (x, y) -> x = a.[0] && y = a.[1])
      |> Option.map (fun i ->
          0.01 * float (System.BitConverter.ToInt32 (d, i + 2)))
      |> function None -> nan | Some v -> v