HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Trim, LINQ style

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
linqtrimstyle

Problem

How do I improve the following?

List list = new List { 1,2,3,0,5,7,0,6,0,0 };
list.Reverse();
list = list.SkipWhile(l => l == 0).ToList();
list.Reverse();


The goal is to trim trailing zeroes.

Solution

Reversing the list twice as well as creating a new List just to remove trailing zeros is very inefficient.

Running the below vs the other answers in a loop 10 million times shows this performs about 5 times faster than the accepted answer, and about 3 times faster than list.Take(list.FindLastIndex(item => item != 0) + 1).ToList();:

List list = new List { 1, 2, 3, 0, 5, 7, 0, 6, 0, 0 };
for (int index = list.Count - 1; index >= 0 && list[index] == 0; index--)
{
    list.RemoveAt(index);
}


Update (again)

I've redone the measurements using varying inputs. Each answer's code is executed in a loop 10 million times. I've also moved the list creation out of the loop so it doesn't pollute what I'm trying to measure.

1 = Reverse + SkipWhile

2 = For loop + RemoveAt

3 = Take + FindLastIndex

4 = GetRange + FindLastIndex

5 = For loop + FindLastIndex + RemoveRange

Empty lists:

  • 2258 ms



  • 62 ms



  • 844 ms



  • 488 ms



  • 138 ms



List of 100 non-zeros:

  • 52334 ms



  • 490 ms



  • 34056 ms



  • 2170 ms



  • 665 ms



List of 100 non-zeros, 1 trailing zero:

  • 53420 ms



  • 1297 ms



  • 34268 ms



  • 2360 ms



  • 1981 ms



List of 100 non-zeros, 100 trailing zeros:

  • 67423 ms



  • 12483 ms



  • 41153 ms



  • 8112 ms



  • 6958 ms



List of 100 zeros:

  • 15711 ms



  • 10448 ms



  • 5404 ms



  • 5075 ms



  • 5474 ms



Code used for testing:

class Program
{
    static List[] lists;
    static List nonZeros = new List(Enumerable.Range(1, 100));
    static List zeros = new List(Enumerable.Repeat(0, 100));
    const int max = 10000000;

    static void Main(string[] args)
    {
        List result = null;
        RecreateLists();

        var sw = Stopwatch.StartNew();
        for (int i = 0; i  x == 0).Reverse().ToList();
        }
        sw.Stop();
        Console.WriteLine(" 1. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        for (int i = 0; i = 0 && lists[i][index] == 0; index--)
            {
                lists[i].RemoveAt(index);
            }
        }
        sw.Stop();
        Console.WriteLine(" 2. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        for (int i = 0; i  item != 0) + 1).ToList();
        }
        sw.Stop();
        Console.WriteLine(" 3. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        for (int i = 0; i  x != 0) + 1);
        }
        sw.Stop();
        Console.WriteLine(" 4. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        int toRemove;
        for (int i = 0; i  item != 0) + 1;
            lists[i].RemoveRange(toRemove, lists[i].Count - toRemove);
        }
        sw.Stop();
        Console.WriteLine(" 5. {0} ms", sw.ElapsedMilliseconds);

        lists = null;
        GC.Collect();

        Console.WriteLine("\nComplete!");
        Console.ReadLine();
    }

    static void RecreateLists()
    {
        lists = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        lists = new List[max];
        var combined = new List(nonZeros);
        combined.AddRange(zeros);
        for (int i = 0; i (combined);
        }
    }
}

Code Snippets

List<int> list = new List<int> { 1, 2, 3, 0, 5, 7, 0, 6, 0, 0 };
for (int index = list.Count - 1; index >= 0 && list[index] == 0; index--)
{
    list.RemoveAt(index);
}
class Program
{
    static List<int>[] lists;
    static List<int> nonZeros = new List<int>(Enumerable.Range(1, 100));
    static List<int> zeros = new List<int>(Enumerable.Repeat(0, 100));
    const int max = 10000000;

    static void Main(string[] args)
    {
        List<int> result = null;
        RecreateLists();

        var sw = Stopwatch.StartNew();
        for (int i = 0; i < max; i++)
        {
            result = Enumerable.Reverse(lists[i]).SkipWhile(x => x == 0).Reverse().ToList();
        }
        sw.Stop();
        Console.WriteLine(" 1. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        for (int i = 0; i < max; i++)
        {
            for (int index = lists[i].Count - 1; index >= 0 && lists[i][index] == 0; index--)
            {
                lists[i].RemoveAt(index);
            }
        }
        sw.Stop();
        Console.WriteLine(" 2. {0} ms", sw.ElapsedMilliseconds);

        RecreateLists();
        sw.Restart();
        for (int i = 0; i < max; i++)
        {
            result = lists[i].Take(lists[i].FindLastIndex(item => item != 0) + 1).ToList();
        }
        sw.Stop();
        Console.WriteLine(" 3. {0} ms", sw.ElapsedMilliseconds);


        RecreateLists();
        sw.Restart();
        for (int i = 0; i < max; i++)
        {
            result = lists[i].GetRange(0, lists[i].FindLastIndex(x => x != 0) + 1);
        }
        sw.Stop();
        Console.WriteLine(" 4. {0} ms", sw.ElapsedMilliseconds);


        RecreateLists();
        sw.Restart();
        int toRemove;
        for (int i = 0; i < max; i++)
        {
            toRemove = lists[i].FindLastIndex(item => item != 0) + 1;
            lists[i].RemoveRange(toRemove, lists[i].Count - toRemove);
        }
        sw.Stop();
        Console.WriteLine(" 5. {0} ms", sw.ElapsedMilliseconds);


        lists = null;
        GC.Collect();

        Console.WriteLine("\nComplete!");
        Console.ReadLine();
    }

    static void RecreateLists()
    {
        lists = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        lists = new List<int>[max];
        var combined = new List<int>(nonZeros);
        combined.AddRange(zeros);
        for (int i = 0; i < max; i++)
        {
            lists[i] = new List<int>(combined);
        }
    }
}

Context

StackExchange Code Review Q#124537, answer score: 8

Revisions (0)

No revisions yet.