按特定顺序排序数组

时间:2014-11-25 11:21:48

标签: c# arrays

我有这个整数数组: -

int[] numbers = new int[] { 10, 20, 30, 40 };

我正在尝试创建一个数组,它将包含第一个元素,最后一个元素,第二个元素,倒数第二个元素等等。

所以,我的结果输出是: -

int[] result = {10,40,20,30};

这是我的方法,在一个循环中从第一个开始直到中间和在第二个循环从最后开始并到达中间并相应地选择项目,但我完全搞砸了。这是我尝试过的代码: -

private static IEnumerable<int> OrderedArray(int[] numbers)
{
    bool takeFirst = true;
    if (takeFirst)
    {
        takeFirst = false;
        for (int i = 0; i < numbers.Length / 2; i++)
        {
            yield return numbers[i];
        }
    }
    else
    {
        takeFirst = true;
        for (int j = numbers.Length; j < numbers.Length / 2; j--)
        {
            yield return numbers[j];
        }
    }
}

需要帮助。

7 个答案:

答案 0 :(得分:5)

你可以试试这个:

int[] result = numbers.Zip(numbers.Reverse(), (n1,n2) => new[] {n1, n2})
                      .SelectMany(x =>x)
                      .Take(numbers.Length)
                      .ToArray();

说明:此方法基本上将原始集合的元素与其反向排序集合的元素配对(使用Zip)。所以你得到了一些像[first,last],[second,second from last]等对的集合。

然后将这些对的集合展平为单个集合(使用SelectMany)。因此,该集合变为[第一个,最后一个,第二个,第二个,从最后一个,......]。

最后,我们将元素的数量限制为原始数组的长度(n)。由于我们迭代了两倍的元素(正常和反向),因此迭代通过n元素允许我们在集合的中间停止。


作为一种不同的方法,这是对现有方法的修改:

private static IEnumerable<int> OrderedArray(int[] numbers)
{
    var count = (numbers.Length + 1) / 2;
    for (int i = 0; i < count; i++)
    {
        yield return numbers[i];

        int reverseIdx = numbers.Length - 1 - i;
        if(i != reverseIdx)
            yield return numbers[reverseIdx];
    }
}

答案 1 :(得分:4)

确定,

public static class Extensions
{
    public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
    {
        var length = source.Count;        
        var limit = length / 2;
        for (var i = 0; i < limit; i++)
        {
           yield return source[i];
           yield return source[length - i - 1];
        }

        if (length % 2 > 0)
        {
            yield return source[limit];
        }
    }
}

你可以这样使用,

var result = numbers.EndToEnd().ToArray();

更优化,

public static class Extensions
{
    public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
    {
        var c = source.Count;
        for (int i = 0, f = 0, l = c - 1; i < c; i++, f++, l--)
        {
            yield return source[f];
            if (++i == c)
            {
               break;
            }

            yield return source[l];
        }
    }
}

不需要分割或模数。

答案 2 :(得分:3)

使用简单的for;

int len = numbers.Length;
int[] result = new int[len];

for (int i = 0, f = 0, l = len - 1; i < len; f++, l--)
{
    result[i++] = numbers[f];

    if (f != l)
        result[i++] = numbers[l];
}

答案 3 :(得分:1)

基于Selman22现已删除的答案:

int[] numbers = new int[] { 10, 20, 30, 40 };
int[] result = numbers
  .Select((x,idx) => idx % 2 == 0 
                     ? numbers[idx/2] 
                     : numbers[numbers.Length - 1 -idx/2])
  .ToArray();
  result.Dump();

(最后一行是LinqPad输出结果的方式)

或者按照Jeppe Stig Nielsen的建议以较少的LINQy形式

var result = new int[numbers.Length]; 
for (var idx = 0; idx < result.Length; idx++) { 
    result[idx] = idx % 2 == 0 ? numbers[idx/2] : numbers[numbers.Length - 1 -idx/2]; 
}

原则是你有两个序列,一个用于偶数元素(在结果中),一个用于奇数。偶数计算数组的前半部分,赔率计算后半部分。

对Selman代码的唯一修改是将/2添加到索引中以使其在右半部分逐个计数,而输出索引(在这种情况下基本上是idx)依赖。< / p>

答案 4 :(得分:0)

想出了这个

static void Main(string[] args)
    {
        List<int> numbers = new List<int>() { 10, 20, 30, 40, 50, 60, 70};
        List<int> numbers2 = new List<int>();

        int counter1 = 0;
        int counter2 = numbers.Count - 1;
        int remainder = numbers.Count % 2 == 0 ? 1: 0;
        while (counter1-1 < counter2)
        {
            if (counter1 + counter2 % 2 == remainder)
            {
                numbers2.Add(numbers[counter1]);
                counter1++;
            }
            else
            {
                numbers2.Add(numbers[counter2]);
                counter2--;
            }
        }
        string s  = "";
        for(int a = 0; a< numbers2.Count;a++)
            s+=numbers2[a] + " ";
        Console.Write(s);
        Console.ReadLine();
    }

答案 5 :(得分:0)

想出了这个

    public int[] OrderedArray(int[] numbers)
    {
        int[] final = new int[numbers.Length];
        var limit=numbers.Length;
        int last = numbers.Length - 1;
        var finalCounter = 0;

        for (int i = 0; finalCounter < numbers.Length; i++)
        {
            final[finalCounter] = numbers[i];
            final[((finalCounter + 1) >= limit ? limit - 1 : (finalCounter + 1))] = numbers[last];
            finalCounter += 2;
            last--;
        }

        return final;
    }

答案 6 :(得分:0)

这个迟到的答案从现有的答案中偷了很多!

这个想法是一次分配整个result数组(因为它的长度是已知的)。然后从source的一端首先填写所有偶数索引成员。最后从source的后端填写奇数条目。

public static TElement[] EndToEnd<TElement>(this IReadOnlyList<TElement> source)
{
  var count = source.Count;

  var result = new TElement[count];
  for (var i = 0; i < (count + 1) / 2; i++)
    result[2 * i] = source[i];
  for (var i = 1; i <= count / 2; i++)
    result[2 * i - 1] = source[count - i];

  return result;
}