Deleting same elements in array C# [duplicate] - c#

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);
}
}

Related

C# Select some lists in many lists that look like a list

Sorry if the header made you confused.
This thread looks similar header but that is actually different Selecting some lists from a list of lists.
I want to Select some lists in many lists that look like a list
Sample:
// data source
List<List<int>> sources = new List<List<int>>();
sources.Add(new List<int>(){1, 2, 3, 4});
sources.Add(new List<int>(){1, 2, 3, 4, 5});
sources.Add(new List<int>(){1, 2, 3, 4, 5, 6});
sources.Add(new List<int>(){1, 2, 99, 3, 4, 5, 6});
sources.Add(new List<int>(){1, 3, 99, 2, 4, 5});
sources.Add(new List<int>(){5, 4, 3, 2, 1});
sources.Add(new List<int>(){1, 2, 4, 5, 6});
sources.Add(new List<int>(){1, 2, 69, 3, 4, 5});
// the list that we want to find lists similar to this
List<int> current = new List<int>() {1, 2, 3, 4, 5};
The list contain not-important element, can be ignored. Updated! In the case its elements are not appeared in current:
List<int> flexible = new List<int>() {99, 66, 123123, 2};// <= updated!
The function I want to write:
void FilterA(List<int> current, List<List<int>> sources, List<int> flexible) {}
How to make FilterA output these list (Lists chosen)? Printing functions are not required.
Lists chosen
1 2 3 4 5 // exactly the same !
1 2 3 4 5 6 // same first 5 elements, the rests are not important
1 2 99 3 4 5 6 // 99 is in flexible list, after ignored that is 1 2 3 4 5 6
// Updated! Ignore 99 because it is not in list current
Lists ignored
1 2 3 4 // missing 5 in current
1 3 99 2 4 5 // 99 is in flexible list, after ignored that is 1 3 2 4 5
5 4 3 2 1 // wrong order
1 2 4 5 6 // missing 3 in current
1 2 69 3 4 5 // 69 is not in flexible list
Thank you very much!
--- Updated ---
If elements in list flexible appeared in list current, they must not be excluded.
The answer of #Sweeper is nice.
p/s: In the case not any element of flexible appear in current, #TheGeneral 's answer is great, runs great performance.
Update after clarification
The premise is, remove flexible with Except, Take n to then compare with SequenceEqual.
Note : All three methods have linear time complexity O(n)
var results = sources.Where(x =>
x.Except(flexible)
.Take(current.Count)
.SequenceEqual(current));
Output
1, 2, 3, 4, 5
1, 2, 3, 4, 5, 6
1, 2, 99, 3, 4, 5, 6
Full demo here
Additional Resources
Enumerable.Except
Produces the set difference of two sequences.
Enumerable.Take
Returns a specified number of contiguous elements from the start of a
sequence.
Enumerable.SequenceEqual
Determines whether two sequences are equal according to an equality
comparer.
You should write a method that determines whether one list (candidate) should be chosen:
public static bool ShouldChoose(List<int> candidate, List<int> current, List<int> flexible) {
int candidateIndex = 0;
foreach (int element in current) {
if (candidateIndex >= candidate.Count) {
return false;
}
// this loop looks for the next index in "candidate" where "element" matches
// ignoring the elements in "flexible"
while (candidate[candidateIndex] != element) {
if (!flexible.Contains(candidate[candidateIndex])) {
return false;
}
candidateIndex++;
}
candidateIndex++;
}
return true;
}
Then you can do a Where filter:
var chosenLists = sources.Where(x => ShouldChoose(x, current, flexible)).ToList();
foreach (var list in chosenLists) {
Console.WriteLine(string.Join(", ", list));
}
This works for me:
var results =
sources
.Where(source => source.Except(flexible).Count() >= current.Count())
.Where(source => source.Except(flexible).Zip(current, (s, c) => s == c).All(x => x))
.ToList();

Sort an array in the same order as a given array

I have an array of unique values specified in some arbitrary order; I have another array of (nearly) the same values as the first array, but some values may be missing, and they are ordered in a completely different way.
How do I order values in the second array in the same order as the first one?
UPD for example:
array 1: 4, 8, 2, 5, 9, 3
array 2: 5, 8, 4, 2
required result: 4, 8, 2, 5
You could check that each element in array 1 exists in array 2 and take them in that order:
var result = array1.Where(a => array2.Contains(a));
int[] array1 = new int[] { 4, 8, 2, 5, 9, 3 };
int[] array2 = new int[] { 5, 8, 4, 2 };
array2 = array1.Intersect(array2).ToArray();
Ok,lets consider logic than code.
If we consider the case where second array is subset of the first array We can do One thing. let's create an array of type Boolean of size first array. Consider each element of second array and traverse through first array. If you find a match then make corresponding Boolean index as TRUE. Finally you will get a Boolean array of TRUE and FALSE combination. then you can print all indexes of first array with Boolean value TRUE.

How to split an array to 2 arrays with odd and even indices respectively? [duplicate]

This question already has answers here:
Getting odd/even part of a sequence with LINQ
(8 answers)
Closed 6 years ago.
How to split an array to 2 arrays with odd and even indices respectively? For example
int[] a = new int[]{1, 3, 7, 8};
then get two arrays
a1: {1, 7}
a2: {3, 8}
Simple using the overload of Where than contains the index which:
Filters a sequence of values based on a predicate. Each element's
index is used in the logic of the predicate function.
int[] a = new int[] { 1, 3, 7, 8 };
int[] aEven = a.Where((x, i) => i % 2 == 0).ToArray();
int[] aOdd = a.Where((x, i) => i % 2 != 0).ToArray();

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

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()

Efficiently adding multiple elements to the start of a List in C#

I have a list that I would like to add multiple elements to the start of. Adding to the start is linear time because it is backed by an array and has to be moved one at a time, and I cannot afford to do this as many times as I would have to if I implemented this the naive way.
If I know exactly how many elements I am about to add, can I shift them all that much so that the linearity only has to happen once?
List<int> myList = new List<int> { 6, 7, 8, 9, 10 };
//Desired list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//Unacceptable
for (int i = 5; i>=0; i--){
myList.Insert(0,i);
}
//Is this concept possible?
int newElements = 5;
for (int i = myList.Count; i>=0; i--){
myList[i+newElements] = myList[i];//This line is illegal, Index was out of range
}
for (int i = 0; i< newElements; i++){
myList[i] = i+1;
}
In this specific instance, access needs to be constant time, hence the usage of List. I need to be able to add elements to both the start and end of the data structure as fast as possible. I am okay with O(m) where m is the number of elements being added (since I don't think that can be avoided) but O(m*n) where n is the number of elements in the existing structure is far too slow.
You can use InsertRange which will be linear if the inserted collection implements ICollection<T>:
var newElements = new[] { 0, 1, 2, 3, 4 };
myList.InsertRange(0, newElements);
myList.InsertRange(0, new List<int> { 1, 2, 3, 4, 5 });
If your new elements are already in a List, you could use List.AddRange to add your "old" list to the end of the to-be-added-items-list.
I would imagine myList.InsertRange(0, newElements) would suit you well. Microsoft will have made that as efficient as it can be.

Categories