patterncsharpMinor
Trim, LINQ style
Viewed 0 times
linqtrimstyle
Problem
How do I improve the following?
The goal is to trim trailing zeroes.
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
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:
List of 100 non-zeros:
List of 100 non-zeros, 1 trailing zero:
List of 100 non-zeros, 100 trailing zeros:
List of 100 zeros:
Code used for testing:
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.