将一个数组分成两个数组 C#

37

编辑:我尝试了Take/Skip方法,但是出现了以下错误:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to   
'string[]'. An explicit conversion exists (are you missing a cast?)

我不知道我做错了什么,因为我复制了Saeed的代码。

我有一个字符串数组(包含20到300个项),我想将其分成2个单独的数组,从第一个数组的中间开始分割。

我知道如何使用for循环来完成这个任务,但我想知道是否有更快/更好的方法。如果数组中有奇数项,我也需要能够正确地将其拆分,例如:

string[] words = {"apple", "orange", "banana", "pear", "lemon"};
string[] firstarray, secondarray;
SplitArray(words, out firstarray, out secondarray); // Or some other function
// firstarray has the first 3 of the items from words, 'apple', 'orange' and 'banana'
// secondarray has the other 2, 'pear' and 'lemon'

为了解决您的转换问题,请在Take和Skip方法后添加.ToArray() - Bob Vale
7个回答

78

你可以使用LINQ:

firstArray = array.Take(array.Length / 2).ToArray();
secondArray = array.Skip(array.Length / 2).ToArray();

尽管原始数组的大小为偶数,为什么这样做起作用呢?

第一个数组(firstArray)获取了array.Length / 2个元素,而第二个数组(second one)则跳过了前面array.Length / 2个元素,这意味着这两个数组之间没有冲突。当然,如果元素数量是奇数,则无法将数组分成两个相等大小的部分。

如果你想在奇数情况下增加第一半的元素,请按照以下步骤操作:

firstArray = array.Take((array.Length + 1) / 2).ToArray();
secondArray = array.Skip((array.Length + 1) / 2).ToArray();

@ Saaed:它与所述的要求不匹配。根据示例数据,'firstArray'将包含'{"apple","orange"}',而'secondArray'将包含'{"banana","pear","lemon"}'。Matthew表示第一个数组应该是两个数组中较长的一个;这是否真的是个问题取决于他! - LukeH
1
@LukeH,谢谢,我没有看到他的评论,我根据你的提示更新了答案。(另外,我的名字是Saeed,不是Saaed :)) - Saeed Amiri
1
@LukeH,第一个数组或第二个数组多一个元素并不重要,但感谢您的评论! - matthewr
你说过“更快/更好”,所以我对这个方法进行了基准测试,与使用2个for循环的方法进行了比较。在一百万次迭代中,这个答案需要613.11纳秒,而for循环方法只需要77.21纳秒。如果执行时间很重要,那么请使用更低级别的方法,否则,Linq似乎更好,因为它更容易维护。 - StuperUser
1
@saeed +1 因为你是我的朋友和同事 + 有用的回答 ;) - Mohsen Heydari
显示剩余6条评论

8
string[] words = {"apple", "orange", "banana", "pear", "lemon"};
int mid = words.Length/2;
string[] first = words.Take(mid).ToArray();
string[] second = words.Skip(mid).ToArray();

7
如果您不想或不能使用LINQ,您可以简单地执行以下操作:
    string[] words = { "apple", "orange", "banana", "pear", "lemon" };
    string[] firstarray, secondarray;
    int mid = words.Length / 2;
    firstarray = new string[mid];
    secondarray = new string[words.Length - mid];
    Array.Copy(words, 0, firstarray, 0, mid);
    Array.Copy(words, mid, secondarray, 0, secondarray.Length);

4
一个更一般化的方法是将其分成您指定的多个部分:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
        {
          return list.Select((item, index) => new {index, item})
                       .GroupBy(x => (x.index + 1) / (list.Count()/parts) + 1)
                       .Select(x => x.Select(y => y.item));
        }

*编辑 感谢skarmats


2
这将改变事物的顺序。因此,第n个结果数组将不对应于源的第n个部分。 - skarmats
已更新以防止数组剥离。 - Totero

3
string[] words = { "apple", "orange", "banana", "pear", "lemon" };
var halfWay = words.Length/2;

var firstHalf = words.Take(halfWay);
var secondHalf = words.Skip(halfWay);

2
你可以使用范围表示法轻松实现这一点:
var x = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
var pivot = x.Length / 2;
var p1 = x[..pivot];
var p2 = x[pivot..];

-2

以防万一,如果有人想使用函数:

    static void Main(string[] args)
    {
        string[] ar = { "apple", "orange", "banana", "pear", "lemon" };

        int half =  ar.Length / 2;

        //  Console.WriteLine(string.Join(',', Split(ar,0, half)));

        Console.WriteLine(string.Join(',', Split(ar,half, ar.Length)));

        Console.ReadKey();
    }


    public static IEnumerable<T> Split<T>(IEnumerable<T> items, int start, int end)
    {
        return items.Skip(start).Take(end);
    }

1
你已经把易于理解的“Skip”和“Take”操作符替换成了不易于理解的“SplitArray”函数,该函数只能在数组(而非“IEnumerable<T>”)上运行,并且引入了没有明确含义的“start”和“end”参数。 - Enigmativity
非常感谢您的评论。我实际上花了时间测试它,它适用于字符串和整数,我想其他类型也是如此。现在,谈到起点和终点,我必须不同意起点和终点很难理解。基本上,您想要拆分一个数组,但您想从哪里开始拆分以及在哪里结束拆分。这就是为什么我认为它很容易理解。我感谢您的评论,并希望从您那里学习,如果您对我所提到的有任何疑虑或评论。 :) - Khaled Saleh
更新了该函数,使其能够处理IEnumerable<T>而不仅仅是数组。 - Khaled Saleh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接