C# removing duplicates in List<int> [duplicate] - c#

This question already has answers here:
Fastest way to Remove Duplicate Value from a list<> by lambda
(7 answers)
Closed 6 years ago.
So my code is basically this:
List list = new List(new int[] { 1, 5, 8, 8, 8, 2, 3, 3, 4, });
list = RemoveDuplicats(list);
public static List<int> RemoveDuplicats(List<int> list)
{
int i = 0;
while (i<list.Count)
{
if (list[i] == list[i+1])
{
list.RemoveAt(list[i + 1]);
return list;
}
i++;
}
return list;
}
It seems like RemoveAt is not working or it's being skipped entirely. So what i should be getting is 1,5,8,2,3,4 but it just prints original list. Where'd i go wrong?

Use the Distinct IEnumerable extension
List<int> list = new List<int>() { 1, 5, 8, 8, 8, 2, 3, 3, 4, };
list = list.Distinct().ToList();
Returns distinct elements from a sequence by using the default
equality comparer to compare values.
However, a part from this solution that is explained in many duplicates of your question, I wish to explain your error.
Your current code doesn't work correctly because when you find the first duplicate you call RemoveAt passing the value of the element (8), not the index (2) of the element to be removed as RemoveAt requires. And you are lucky that this doesn't create an Out of Range exception. Moreover you exit immediately with a return leaving the other duplicates in place.
If you still want to use an hand made remove code you could try with this
public List<int> RemoveDuplicats(List<int> list)
{
int i = 0;
List<int> distinctElements = new List<int>();
while (i < list.Count)
{
if (!distinctElements.Contains(list[i]))
distinctElements.Add(list[i]);
i++;
}
return distinctElements;
}

I would use distinct.
list.Distinct().ToList()

Related

Fast Sequence checking in a List<int> [duplicate]

This question already has answers here:
Is there a built-in method to compare collections?
(15 answers)
Functional way to check if array of numbers is sequential
(7 answers)
Closed 4 years ago.
I am looking for a faster and more accurate way to check a Sequence:
List<int> sequence = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7 … 41}
private bool IsSequential(List<int> sequence)
{
int S = sequence[0];
int T = sequence[sequence.Count- 1];
List<int> Possible = Enumerable.Range(S, T).ToList();
List<int> Except = sequence.Except(Possible).ToList();
if (Except.Count == 0)
return true;
else
return false;
}
My code returns 1 if the list is the same, I have some sort of count issue?
I wonder if there is a better way to check an integer sequence: 200, 201, 202... and so on.
Some Sequences may be out of sequence: 200, 210, 203, 204... I need to identify this issue.
Thanks
You can try like following using SequenceEqual.
List<int> sequence = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7 };
bool isInSequence = sequence.SequenceEqual(Enumerable.Range(sequence[0], sequence.Count()));

How to delete a numbers from Array that contained in another Array? [duplicate]

This question already has answers here:
Getting the "diff" between two arrays in C#?
(5 answers)
Closed 6 years ago.
How I can delete a numbers from Array “a” that contained in Array “b”?
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] b = {3, 9};
You cannot delete items from an array. What you can do is create another array that contains the items from a except the items in b and assign it to variable a like this:
a = a.Except(b).ToArray();
You can copy b into a list, and then delete elements from it.
List<int> bList = new List<int>();
bList.AddRange(b);
foreach (int check in a)
{
if (bList.Contains(check))
{
bList.Remove(check);
}
}
b = bList.ToArray();

Check times a value is next to the same value in an array

Lets say I have this array on C#:
int myList = {1,4,6,8,3,3,3,3,8,9,0}
I want to know if a value (lets say from 0-9) is next to itself in the list and how many times. In this case, the value 3 is next to itself and it has 4 repetitions. If I have a list {0,1,2,3,4,5,5,6,7} the value 5 is next to itself and has 2 repetitions.
Repetitions have a limit of 5. No value can be repeated more than 5 times. The far I went is making if statements, but I know there's a better way of doing it.
The standard of question is not that good but writing the answer
int lastValue = myList[0];
int times = 0;
foreach (int value in myList) {
if (lastValue == value) {
times++;
}
else if (times <= 1) {
lastValue = value;
times = 1;
}
else
break;
}
You only have to iterate on your list and keep a counter that will count only the consecutive duplicate integer.
If you want a neater solution, you might look at using an open source library called morelinq (by Jon Skeet and few others) on nuget. It has useful extension methods for LINQ.
One of them is called GroupAdjacent, which is applicable to your problem.
var testList = new[] { 1, 4, 6, 8, 3, 3, 3, 3, 8, 9, 0 };
var groups = testList.GroupAdjacent(t => t);
var groupsWithMoreThanOneMember = groups.Where(g => g.Count() > 1);

Deleting same elements in array C# [duplicate]

This question already has answers here:
How do I remove duplicates from a C# array?
(28 answers)
Closed 9 years ago.
If I have one array for example [1 4 3 7 4 9 5 1 5 6 3].
How to delete repetitive numbers and give in the output array like this [1 4 3 7 9 5 6]?
Distinct()
var distinctArray = myArray.Distinct().ToArray();
You can call your array in a HashSet<int> constructor. HashSet is a kind of optimized collection. It's constructor eliminates the non-unique elements.
Here an example in LINQPad;
var array = new[]{1, 4, 3, 7, 4, 9, 5, 1, 5, 6, 3};
HashSet<int> h = new HashSet<int>(array);
h.ToArray().Dump();
Here a result;
What about this :
int[] arr = { 1, 4, 3, 7, 4, 9, 5, 1, 5, 6, 3 };
foreach (int item in arr.Distinct())
{
Console.WriteLine(item);
}
and you can also assign in a array like this:
int[] unique = arr.Distinct().ToArray();
Couple of suggestions found searching:
1.)
int[] s = { 1, 2, 3, 3, 4};
int[] q = s.Distinct().ToArray();
2.) The easiest solution will be to simply sort the array (takes O(n log n) with standard implementation if you may use them. otherwise consider making an easy randomized quicksort (code is even on wikipedia)).
Afterwards scan it for one additional time. During that scan simple eliminate consecutive identical elements.
If you want to do it in O(n), you can also use a HashSet with elements you have already seen. Just iterate once over your array, for each element check if it is in your HashSet.
If it isn't in there, add it. If it is in there, remove it from the array.
Note, that this will take some additional memory and the hashing will have a constant factor that contributes to your runtime. Althought the time complexity is better, the practical runtime will only be onyl be faster once you exceed a certain array size
If you, for whatever reason, do not want to use Linq:
List<int> distinctList = new List<int>();
foreach (var num in numberList)
{
if (!distinctList.Contains(num))
{
distinctList.Add(num);
}
}

How to select values within a provided index range from a List using LINQ

I am a LINQ newbie trying to use it to acheive the following:
I have a list of ints:-
List<int> intList = new List<int>(new int[]{1,2,3,3,2,1});
Now, I want to compare the sum of the first three elements [index range 0-2] with the last three [index range 3-5] using LINQ. I tried the LINQ Select and Take extension methods as well as the SelectMany method, but I cannot figure out how to say something like
(from p in intList
where p in Take contiguous elements of intList from index x to x+n
select p).sum()
I looked at the Contains extension method too, but that doesn't see to get me what I want. Any suggestions? Thanks.
Use Skip then Take.
yourEnumerable.Skip(4).Take(3).Select( x=>x )
(from p in intList.Skip(x).Take(n) select p).sum()
You can use GetRange()
list.GetRange(index, count);
For larger lists, a separate extension method could be more appropriate for performance. I know this isn't necessary for the initial case, but the Linq (to objects) implementation relies on iterating the list, so for large lists this could be (pointlessly) expensive. A simple extension method to achieve this could be:
public static IEnumerable<TSource> IndexRange<TSource>(
this IList<TSource> source,
int fromIndex,
int toIndex)
{
int currIndex = fromIndex;
while (currIndex <= toIndex)
{
yield return source[currIndex];
currIndex++;
}
}
Starting from .NET 6 it is possible to use range syntax for Take method.
List<int> intList = new List<int>(new int[]{1, 2, 3, 3, 2, 1});
// Starting from index 0 (including) to index 3 (excluding) will select indexes (0, 1, 2)
Console.WriteLine(intList.Take(0..3).Sum()); // {1, 2, 3} -> 6
// By default is first index 0 and can be used following shortcut.
Console.WriteLine(intList.Take(..3).Sum()); // {1, 2, 3} -> 6
// Starting from index 3 (including) to index 6 (excluding) will select indexes (3, 4, 5)
Console.WriteLine(intList.Take(3..6).Sum()); // {3, 2, 1} -> 6
// By default is last index lent -1 and can be used following shortcut.
Console.WriteLine(intList.Take(3..).Sum()); // {3, 4, 5} -> 6
// Reverse index syntax can be used. Take last 3 items.
Console.WriteLine(intList.Take(^3..).Sum()); // {3, 2, 1} -> 6
// No exception will be raised in case of range is exceeded.
Console.WriteLine(intList.Take(^100..1000).Sum());
So simply put, intList.Take(..3).Sum() and intList.Take(3..).Sum() can be used with .NET 6.
To filter by specific indexes (not from-to):
public static class ListExtensions
{
public static IEnumerable<TSource> ByIndexes<TSource>(this IList<TSource> source, params int[] indexes)
{
if (indexes == null || indexes.Length == 0)
{
foreach (var item in source)
{
yield return item;
}
}
else
{
foreach (var i in indexes)
{
if (i >= 0 && i < source.Count)
yield return source[i];
}
}
}
}
For example:
string[] list = {"a1", "b2", "c3", "d4", "e5", "f6", "g7", "h8", "i9"};
var filtered = list.ByIndexes(5, 8, 100, 3, 2); // = {"f6", "i9", "d4", "c3"};

Categories