2

ジェネリック配列のString.Split機能を模倣したい。

私は、ダブルスでうまくいくと思われるこの方法を思いつきました。

public static double[][] Split(this double[] vals, double t)
{
    List<double[]> ret = new List<double[]>();

    int last = -1;
    for (int i = 0; i <= vals.Length; i++)
    {
        if (i != vals.Length && vals[i] != t)
            continue;

        int len = i - last - 1;
        if (len <= 0)
        {
            last = i;
            continue;
        }

        double[] arr = new double[len];
        Array.Copy(vals, last + 1, arr, 0, len);
        last = i;

        ret.Add(arr);
    }

    return ret.ToArray();
}

そして、これはジェネリック用です...

public static T[][] Split<T>(this T[] vals, T t) where T : EqualityComparer<T>
{
    List<T[]> ret = new List<T[]>();

    int last = -1;
    for (int i = 0; i <= vals.Length; i++)
    {
        if (i != vals.Length && vals[i] != t)
            continue;

        int len = i - last - 1;
        if (len <= 0)
        {
            last = i;
            continue;
        }

        T[] arr = new T[len];
        Array.Copy(vals, last + 1, arr, 0, len);
        last = i;

        ret.Add(arr);
    }

    return ret.ToArray();
}

だから、私は3つの質問があります:

  1. これを行うためのより良い/ジェネリックC#の方法はありますか?
  2. テンプレートメソッドを機能させるにはどうすればよいですか? ( でエラーが発生しますvals[i] != t) - 修正済み
  3. どうすればこれを改善できますか(今はちょっと醜いです、IMO)

使用例:

double[] vals = new double[] { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 };
double[][] res = vals.Split(0);

// res[0] = [1, 2]
// res[1] = [2, 3]
// res[2] = [4, 5, 6]
4

3 に答える 3

3

まあ、あなたはそれを怠惰に、そして任意のシーケンスで、そして拡張メソッドとして行うことができます。また、制約を取り除きIComparable<T>ます-とにかくここではそれを使用していません。使用しようとする代わりに を使用することもできますが (これはおわかりのように機能しません)、equalityのみに関心があるため、 を使用する方が理にかなっています。CompareTo!=EqualityComparer<T>

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source,
                                                   T separator)
{
    List<T> currentList = new List<T>();
    var comparer = EqualityComparer<T>.Default;
    foreach (var item in source)
    {
        if (comparer.Equals(item, separator))
        {
            yield return new ReadOnlyCollection<T>(currentList);
            currentList = new List<T>();
        }
        else
        {
            currentList.Add(item);
        }
    }
    yield return new ReadOnlyCollection<T>(currentList);
}

先頭または末尾にセパレータがある場合、またはセパレータが繰り返されている場合、これは空のコレクション返すことに注意してください。もちろん、呼び出し側ではいつでも無視できます。

var nonEmptySequences = original.Split(value)
                                .Where(sequence => sequence.Any());

短いが完全なサンプル コード:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

public static class MoreExtensions
{
    public static IEnumerable<IEnumerable<T>> Split<T>
        (this IEnumerable<T> source, T separator)
    {
        List<T> currentList = new List<T>();
        var comparer = EqualityComparer<T>.Default;
        foreach (var item in source)
        {
            if (comparer.Equals(item, separator))
            {
                yield return new ReadOnlyCollection<T>(currentList);
                currentList = new List<T>();
            }
            else
            {
                currentList.Add(item);
            }
        }
        yield return new ReadOnlyCollection<T>(currentList);
    }

}

class Test
{
    static void Main()
    {
        int[] source = { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 };
        foreach (var group in source.Split(0).Where(x => x.Any()))
        {
            Console.WriteLine("[{0}]", string.Join(",", group));
        }
    }    
}

出力:

[1,2]
[2,3]
[4,5,6]
于 2013-04-05T19:16:50.987 に答える
2

次の一般的な拡張メソッドを使用して、シーケンスを区切り記号で分割できます。デフォルトの比較子を使用して、各項目を区切り記号で比較します。

public static IEnumerable<T[]> Split<T>(this IEnumerable<T> source, T separator)
{
    List<T> bucket = new List<T>();
    var comparer = Comparer<T>.Default;

    foreach (var item in source)
    {
        if (comparer.Compare(item, separator) != 0)
        {
            bucket.Add(item);
            continue;
        }

        if (bucket.Any())
        {
            yield return bucket.ToArray();
            bucket = new List<T>();
        }
    }

    if (bucket.Any())        
        yield return bucket.ToArray();        
}

使用法:

double[] vals = new double[] { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 };
double[][] res = vals.Split(0).ToArray();
于 2013-04-05T19:26:24.580 に答える
2

テンプレートメソッドを機能させるにはどうすればよいですか? ( でエラーが発生しますvals[i] != t)

!=任意の type に対して演算子を定義することはありませんT。しかし、あなたはTimlementsを知っているのでIComparable<T>、それを活用してください:

vals[i].CompareTo(t) != 0
于 2013-04-05T19:16:12.060 に答える