简体   繁体   English

向左拉数组中的所有非零元素-C#

[英]pull all non-zero elements in an array to the left - c#

If I have the following array 如果我有以下数组

{ 1, 0, 0, 1, 2, 0, 1 }

And I want a method that will take the array and change it to 我想要一个方法,它将采用数组并将其更改为

{ 1, 1, 2, 1, 0, 0, 0 }

What would be the best algorithm to do this? 做到这一点的最佳算法是什么? Is it possible to do this in O(N) time? 是否可以在O(N)时间执行此操作?

this question is essentially my exact question except in python not c#, in case I was not clear: (only difference is move the zeros to the right, not left) how to move all non-zero elements in a python list or numpy array to one side? 这个问题本质上是我的确切问题,但在python而非c#中除外,以防我不清楚:(唯一的区别是将零移动到右边,而不是左边) 如何将python列表或numpy数组中的所有非零元素移动到一边?

Thanks 谢谢

EDIT: I've ran into another problem that I didn't consider at first. 编辑:我遇到了另一个我最初没有考虑的问题。 I'm actually trying to run this algorithm on a 2d array, but only on one particular dimension. 我实际上正在尝试在2d数组上运行此算法,但仅在一个特定维度上运行。 how would I change to account for this? 我将如何解决这个问题?

It is possible to do it in O(n) time and O(1) space complexity. 可以在O(n)时间和O(1)空间复杂度中做到这一点。
Start with a low pointer at 0 and a high pointer at last index of the array. 从低指针到0开始,高指针从数组的最后一个索引开始。
Algorithm : 算法
1. Increment low till you find 0, decrement high till you find a non-zero number. 1.递减直到找到0,递减直到找到非零数字。
2. Swap Array[low] and Array[high]. 2.交换Array [low]和Array [high]。
3. Repeat steps 1 and 2 till low is less than high. 3.重复步骤1和2,直到低电平小于高电平为止。

UPDATED FOR 2D ARRAY 二维阵列更新

int[,] array = 
{
    { 1, 0, 0, 1, 2, 0, 1 }, // Row 0
    { 1, 0, 0, 1, 2, 0, 1 }, // Row 1
    { 1, 0, 0, 1, 2, 0, 1 }  // Row 2
};

PullNonZerosToLeft(array, 1);

for (int row = 0; row <= array.GetUpperBound(0); row++)
{
    for (int col = 0; col <= array.GetUpperBound(1); col++)
    {
        Console.Write("{0} ", array[row,col]);
    }
    Console.WriteLine();
}

PullNonZerosToLeft() PullNonZerosToLeft()

public static void PullNonZerosToLeft(int[,] array, int row)
{
    if (row > array.GetUpperBound(0))
    {
        return;
    }

    // Used to keep track of the swap point
    int index = 0;
    for (int i = 0; i <= array.GetUpperBound(1); i++)
    {
        if (array[row, i] == 0)
        {
            continue;
        }

        int temp = array[row, i];
        array[row, i] = array[row, index];
        array[row, index] = temp;
        index++;
    }
}

Results: 结果:

1 0 0 1 2 0 1
1 2 1 1 0 0 0
1 0 0 1 2 0 1

UPDATED FOR JAGGED ARRAY 更新了杂乱的阵列

A non- Linq approach, where you swap all non-zero elements with zero elements. 一种非Linq方法,其中您将所有非零元素交换为零元素。

int[][] array = 
{
    new[] { 1, 0, 0, 1, 2, 0, 1 }, // Row 0
    new[] { 1, 0, 0, 1, 2, 0, 1 }, // Row 1
    new[] { 1, 0, 0, 1, 2, 0, 1 }  // Row 2
};

PullNonZerosToLeft(array, 1);

foreach (int[] row in array)
{
    Console.WriteLine(String.Join(", ", row));
}

PullNonZerosToLeft() PullNonZerosToLeft()

public static void PullNonZerosToLeft(int[][] array, int row)
{
    if (row >= array.Length)
    {
        return;
    }

    // Used to keep track of the swap point
    int index = 0;
    for (int i = 0; i < array[row].Length; i++)
    {
        if (array[row][i] == 0)
        {
            continue;
        }

        int temp = array[row][i];
        array[row][i] = array[row][index];
        array[row][index] = temp;
        index++;
    }
}

Results: 结果:

1, 0, 0, 1, 2, 0, 1
1, 1, 2, 1, 0, 0, 0
1, 0, 0, 1, 2, 0, 1

Here's a way you could do it. 这是您可以做到的方式。

var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var nonZeroes = original.Where(x => x != 0); //enumerate once
var numberOfZeroes = original.Count() - nonZeroes.Count(); 
return nonZeroes.Concat(Enumerable.Repeat(0, numberOfZeroes)).ToArray();

You can just order by n == 0 . 您可以按n == 0排序。

var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var result = original.OrderBy(n => n == 0).ToArray();

Here's a way to do it in O(n) time by creating a new array. 这是通过创建新数组在O(n)时间内完成此操作的方法。 Note that this avoids the penalty of looping through the array a second time to get the count of zeros, as in Dleh's answer. 请注意,这避免了第二次遍历数组以获取零计数的麻烦,就像Dleh的回答一样。

public static int[] PushNonZeroToLeft(int[] aiArray)
{
    var alNew = new List<int>();
    var iZeroCount = 0;

    foreach (int i in aiArray)
        if (i > 0)
            alNew.Add(i);
        else
            iZeroCount++;

    alNew.AddRange(Enumerable.Repeat(0, iZeroCount));

    return alNew.ToArray();
}

Not sure if O(n) can be achieved if you have to mutate the original array... 如果必须对原始数组进行突变,则不确定是否可以实现O(n)。

Here's an O(n) time, O(1) space algorithm for doing what you want. 这是一个O(n)时间,O(1)空间算法,可用于执行您想要的操作。 It will also preserve the order of the non-zero elements. 它还将保留非零元素的顺序。

var array = new []{ 1, 3, 3, 1, 2, 0, 1 };
int j = 0;
for( int i = 0; i < array.Length && j < array.Length; ++i )
{
    if( array[i] != 0 ) continue;

    if( j <= i ) j = i + 1;

    while( j < array.Length && array[j] == 0 ) ++j;

    if( j >= array.Length ) break;

    var t = array[i];
    array[i] = array[j];
    array[j] = t;
}

This is how I'd approach it. 这就是我的处理方式。 Nice and simple. 漂亮又简单。 I didn't run performance tests but would expect it to be a little more performant than some of the suggestions that use LINQ, or create new arrays. 我没有进行性能测试,但是希望它比使用LINQ或创建新阵列的一些建议具有更高的性能。

int[] array = { 1, 0, 0, 1, 2, 0, 1 };

for (int i = 0; i < array.Length; i++)
{
    if (array[i] == 0)
    {
        int j;

        for (j = i + 1; j < array.Length; j++)
        {
            if (array[j] != 0)
                break;
        }

        if (j < array.Length)
        {
            array[i] = array[j];
            array[j] = 0;
        }
        else break;
    }
}

Yes, this is possible to do in O(N) time. 是的,这可以在O(N)时间内完成。

Basically: 基本上:

  1. Loop through the array 遍历数组
  2. For every element you find that is non-zero, copy it 对于您发现的每个非零元素,将其复制
    • First element should be copied to position 0, next to position 1, etc. Keep track of how far you get with this position. 应该将第一个元素复制到位置0,然后复制到位置1,依此类推。跟踪该位置的作用。
  3. When you've looped through it, iterate the position you kept track of through the rest of the array until you reach the end, and keep setting elements to zero as you go. 遍历整个数组后,请遍历数组的其余部分,直到您到达末尾为止,然后将位置设置为零。

The algorithm will copy , not move , so the 3rd point above will make sure any elements we copied but did not subsequently overwrite will be zeroed out afterwards. 该算法将复制 ,而不是move ,因此上面的第三点将确保我们复制但随后没有覆盖的所有元素将在之后被清零。

Here's some example code: 这是一些示例代码:

int next = 0;

// copy all non-zero elements to the start
foreach (var element in collection)
    if (element != 0)
        collection[next++] = element;

// fill remainder with zeroes
while (next < collection.Count)
    collection[next++] = 0;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM