Unique Values from a list of of items in C# - c#

I am having a list:
list = { 1,1,1,2,3,3,3,4,4,5,6,6,6}
Now I want to extract list of unique values.
Final list contains {2,5} only.
How can I do that through LINQ or any other function.

One way would be to use the GroupBy method and filter only those which have a count of 1:
var unique = list.GroupBy(l => l)
.Where(g => g.Count() == 1)
.Select(g => g.Key);

Try This:
List<int> list = new List<int>(new int[]{ 1, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6, 6, 6});
List<int> unique=new List<int>();
int count=0;
bool dupFlag = false;
for (int i = 0; i < list.Count; i++)
{
count = 0;
dupFlag = false;
for(int j=0;j<list.Count;j++)
{
if (i == j)
continue;
if (list[i].Equals(list[j]))
{
count++;
if (count >= 1)
{
dupFlag = true;
break;
}
}
}
if (!dupFlag)
unique.Add(list[i]);
}

Try this code:
var lstUnique =
from t1 in list
group t1 by t1 into Gr
where Gr.Count() == 1
select Gr.Key;

Related

Get the max count of an array inside array?

I have an array inside the array and I want to get the Highest count of that Array,
List<int> badnumber = new List<int>() { 5,4,2, 15 };
int lower = 1;
int upper = 10;
int count = 0;
List<int> goodnumber = new List<int>();
List<List<int>> myList = new List<List<int>>();
for (int i = lower; i <= upper; i++)
{
if (!badnumber.Contains(i))
{
if (!goodnumber.Contains(i))
goodnumber.Add(i);
}
else
{
myList.Add(goodnumber);
goodnumber = new List<int>();
}
if (i == upper) {
myList.Add(goodnumber);
}
}
in myList values are like this
Array 1 : { 1 }
Array 2 : { 3 }
Array 3 : { 0 }
Array 4 : { 6, 7, 8, 9, 10 }
I want to get the count of the highest sequence which is Array 4. and return the count of it which is 5.
how would I get that?
Use following sample
var maxCount = myList.Max(l => l.Count);
Try following :
List<List<int>> myList = new List<List<int>>() {
new List<int> { 1},
new List<int> { 3},
new List<int> { 0},
new List<int> { 6,7,8,9,10}
};
int results = myList.Max(x => x.Count);
Basically your task boils down to the following:
How to get the greatest number in a list
In order to achieve that, you have to iterate that (outer) list, get every elements member you want to compare - in your case the Count - and check if it is greater the current Max:
int max = 0;
foreach(var l in myList)
{
if(l.Count > max)
max = l.Count;
}
or even simpler using linq, see jdweng.
Try below lambda to get index position with count:
int index = 0;
var result = myList.Select(x => new { indexPos = ++index, x.Count }).OrderByDescending(x => x.Count).First();

How to find index of sublist without class C#

I want to find the index of sublist in list route which contains certain value(i), but I don't want to make a class of it.
Here is my code:
var route = new List<List<int>>();
for (int i = 0; i<DC1; ++i)
{
for (int j = 0; j<DC1; ++j)
{
if (routeopt.x[0, j] == 1)
{
List<int> subroute = new List<int>();
if (routeopt.x[i, j] == 1)
{
subroute.Add(j);
route.Add(subroute);
}
}
}
if(i == 0) continue;
for (int j = 1; j<DC1;j++ )
{
if (routeopt.x[i, j] == 1)
route[route.IndexOf(i)].Add ( j);
}
}
foreach (var subroute in route)
{
Console.Write("subroute: ");
foreach (int s in subroute)
Console.Write(s + " ");
Console.WriteLine();
}
For example, based on this code:
for (int j = 1; j < DC1;j++ )
{
if (routeopt.x[i, j] == 1)
route[route.IndexOf(i)].Add(j);
}
I want to make if x[1,3] == 1 then I can add 3 to sublist which contains 1.
this code route.IndexOf(i) is still get red underline, please help how to correct it. Thanks
You can use LINQ's Single method to retrieve the specific list you want given a predicate Contains(i). Here I am looking for the list that contains 6, and adds 7 to it.
var routes = new List<List<int>>()
{
new List<int>() {1, 2, 3},
new List<int>() {4, 5, 6},
};
List<int> targetList = routes.Single(i => i.Contains(6));
targetList.Add(7);
To get specifically the index of that list, then you can use IndexOf method like:
int targetListIndex = routes.IndexOf(targetList); // 1 in this example
Let's start from an example (which we turn into a test later):
List<List<int>> route = new List<List<int>>() {
new List<int>() {1, 2, 3, 4, 5}, // sublist #0: contains value == 4
new List<int>() {7, 8, 2, 9}, // sublist #1: doesn't contain value == 4
new List<int>() {9, 10, 4}, // sublist #2: contains value == 4
};
and we are looking for value within each of sublists
int value = 4;
finally, we want to have sublist indexes as the outcome: 0 and 2.
If it's your case, I suggest using Linq
List<List<int>> route = new List<List<int>>() {
new List<int>() {1, 2, 3, 4, 5},
new List<int>() {7, 8, 2, 9},
new List<int>() {9, 10, 4},
};
int value = 4;
var indexesFound = route
.Select((sublist, index) => new { // eh, new class, but anonymous one
sublist = sublist,
index = index, })
.Where(chunk => chunk.sublist.Contains(value))
.Select(chunk => chunk.index)
.ToArray(); // if you want, say, array materialization
Test
Console.Wrire(string.Join(", ", indexesFound));
Outcome:
0, 2
Edit: if you want to have just one index, you have to specify which one, e.g. for the very first index put .First() instead of .ToArray():
int firstIndexFound = route
.Select((sublist, index) => new { // eh, new class, but anonymous one
sublist = sublist,
index = index, })
.Where(chunk => chunk.sublist.Contains(value))
.Select(chunk => chunk.index)
.First(); // or .Last()

How to iterate a loop every n items

I have a list of items and I need to loop through it so that every n (eg. 3) items are first collected and then processed at once at the n'th item.
I'm doing the following:
List<MyObject> smallList = new List<MyObject>();
for (int i = 0; i < largeList.Count; i++)
{
smallList.Add(largeList[i]);
if (i % 3 == 0 || i >= largeList.Count - 3)
{
//Do somehting with those n items...
}
smallList.Clear();
}
Is there a better way to do the above?
You can also do this with LINQ:
var largeList = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
for (int i = 0; i < largeList.Count; i += 3)
{
var items = largeList.Skip(i).Take(3).ToList();
// do stuff with your 3 (or less items)
}
You can do it with LINQ.
First, "attach" an index to each item:
var indexedItems = largeList.Select((item, index) => new {index, item});
Now group them by their index, while selecting the collection (IEnumerable) of items for each group member:
var groupedItems = indexedItems.GroupBy(indexedItem => indexedItem.index / 3,
indexedItem => indexedItem.item,
(key, items) => items);
Now process each group
foreach(var items in groupedItems) {
// and optionally, .ToList() to have a List<T> instead of IEnumerable<T>
var itemsList = items.ToList();
}
And altogether...:
var indexedItems = largeList.Select((item, index) => new {index, item});
var groupedItems = indexedItems.GroupBy(indexedItem => indexedItem.index / 3,
indexedItem => indexedItem.item,
(key, items) => items);
foreach(var items in groupedItems) {
// Use the items...
}
I suggest using nested loops. Not as pretty as LinQ, but certainly faster.
const int n = 3;
var small = new List();
for(var i=0; i<large.Count; i+=n)
{
small.Clear();
for(var j=i; j < n && j<large.Count; j++)
small.Add(large[j]);
// Do stuff with small
}
However quite similar to what you have now. I think it doesn't get much butter than what you have.
you can use this code:
var MyObjectList = new List<MyObject>();
MyObjectList.Where(a => MyObjectList.IndexOf(a) % 3 == 0).ToList().ForEach(a =>
{
// do your things!
});

C# - How to get complement of two lists without identifiers

I have two lists of the same type. That type does not have an identifier or any other guaranteed way to programatically distinguish.
List A: {1, 2, 2, 3, 5, 8, 8, 8}
List B: {1, 3, 5, 8}
I want the items from A that are not in B.
Desired Result: {2, 2, 8, 8}
If the types had identifiers, I could use a statement like the following...
var result = listA
.Where(a => listB.Where(b => b.Id == a.Id).Count() == 0)
.ToList();
So far, the only way I can do this is with a loop where I add each item the number of times it doesn't appear in the original list.
foreach (var val in listB.Select(b => b.val).Distinct())
{
var countA = listA.Where(a => a.val == val).Count();
var countB = listB.Where(b => b.val == val).Count();
var item = listA.Where(a => a.val == val).FirstOrDefault();
for (int i=0; i<countA-countB; i++)
result.Add(item);
}
Is there a cleaner way to achieve this?
EDIT:
Here is a simplified version of the object in the lists. It's coming from a Web service that's hitting another system.
public class myObject
{
public DateTime SomeDate { get; set; }
public decimal SomeNumber; { get; set; }
public bool IsSomething { get; set; }
public string SomeString { get; set; }
}
The data I am receiving has the same values for SomeDate/SomeString and repeated values for SomeNumber and IsSomething. Two objects might have equal properties, but I need to treat them as distinct objects.
try this:
var listA = new List<Int32> {1, 2, 2, 3, 5, 8, 8, 8};
var listB = new List<Int32> {1, 3, 5, 8};
var listResult = new List<Int32>(listA);
foreach(var itemB in listB)
{
listResult.Remove(itemB);
}
What am I missing?
class Program
{
static void Main(string[] args)
{
List<int> a = new List<int>();
a.Add(1);
a.Add(2);
a.Add(2);
a.Add(3);
a.Add(5);
a.Add(8);
a.Add(8);
a.Add(8);
List<int> b = new List<int>();
b.Add(1);
b.Add(3);
b.Add(5);
b.Add(8);
foreach (int x in b)
a.Remove(x);
foreach (int x in a)
Console.WriteLine(x);
Console.ReadKey(false);
}
}
Are the objects same instances in both lists? If so you can use .Where(a => listB.Where(b => b == a).Count() == 0)
Or
.Where(a => !listB.Any(b => b == a))
You could sort both lists and then iterate through them both at the same time.
public IEnumerable<int> GetComplement(IEnumerable<int> a, IEnumerable<int> b)
{
var listA = a.ToList();
listA.Sort();
var listB = b.ToList();
listB.Sort();
int i=0,j=0;
while( i < listA.Count && j < listB.Count )
{
if(listA[i] > listB[j]) {yield return listB[j];j++;}
else if (listA[i] < listB[j]) {yield return listA[i]; i++; }
else {i++;j++;}
}
while(i < listA.Count)
{
yield return listA[i];
i++;
}
while(j < listB.Count)
{
yield return listB[j];
j++;
}
}
I don't know if this is "cleaner", but it should be more performant on large sets of data.
This is a bit nasty but it does what you want. Not sure about performance though.
var a = new List<int> { 1, 2, 2, 3, 5, 8, 8, 8 };
var b = new List<int> { 1, 3, 5, 8 };
var c = from x in a.Distinct()
let a_count = a.Count(el => el == x)
let b_count = b.Count(el => el == x)
from val in Enumerable.Repeat (x, a_count - b_count)
select val;
Why don't you implement your own equality comparer for your myObject:
public class YourTypeEqualityComparer : IEqualityComparer<myObject>
{
public bool Equals(myObject x, myObject y)
public int GetHashCode(myObject obj)
}
and then use it like this:
var list1 = new List<myObj>();
var list2 = new List<myObj>()
list1.RemoveAll(i =>
list2.Contains(list1),
new YourTypeEqualityComparer()
);
now list1 contains result.

Selecting unique elements from a List in C#

How do I select the unique elements from the list {0, 1, 2, 2, 2, 3, 4, 4, 5} so that I get {0, 1, 3, 5}, effectively removing all instances of the repeated elements {2, 4}?
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
var uniqueNumbers =
from n in numbers
group n by n into nGroup
where nGroup.Count() == 1
select nGroup.Key;
// { 0, 1, 3, 5 }
var nums = new int{ 0...4,4,5};
var distinct = nums.Distinct();
make sure you're using Linq and .NET framework 3.5.
With lambda..
var all = new[] {0,1,1,2,3,4,4,4,5,6,7,8,8}.ToList();
var unique = all.GroupBy(i => i).Where(i => i.Count() == 1).Select(i=>i.Key);
C# 2.0 solution:
static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
{
Dictionary<T, int> counts = new Dictionary<T, int>();
foreach (T item in things)
{
int count;
if (counts.TryGetValue(item, out count))
counts[item] = ++count;
else
counts.Add(item, 1);
}
foreach (KeyValuePair<T, int> kvp in counts)
{
if (kvp.Value == 1)
yield return kvp.Key;
}
}
Here is another way that works if you have complex type objects in your List and want to get the unique values of a property:
var uniqueValues= myItems.Select(k => k.MyProperty)
.GroupBy(g => g)
.Where(c => c.Count() == 1)
.Select(k => k.Key)
.ToList();
Or to get distinct values:
var distinctValues = myItems.Select(p => p.MyProperty)
.Distinct()
.ToList();
If your property is also a complex type you can create a custom comparer for the Distinct(), such as Distinct(OrderComparer), where OrderComparer could look like:
public class OrderComparer : IEqualityComparer<Order>
{
public bool Equals(Order o1, Order o2)
{
return o1.OrderID == o2.OrderID;
}
public int GetHashCode(Order obj)
{
return obj.OrderID.GetHashCode();
}
}
If Linq isn't available to you because you have to support legacy code that can't be upgraded, then declare a Dictionary, where the first int is the number and the second int is the number of occurences. Loop through your List, loading up your Dictionary. When you're done, loop through your Dictionary selecting only those elements where the number of occurences is 1.
I believe Matt meant to say:
static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
{
Dictionary<T, bool> uniques = new Dictionary<T, bool>();
foreach (T item in things)
{
if (!(uniques.ContainsKey(item)))
{
uniques.Add(item, true);
}
}
return uniques.Keys;
}
There are many ways to skin a cat, but HashSet seems made for the task here.
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
HashSet<int> r = new HashSet<int>(numbers);
foreach( int i in r ) {
Console.Write( "{0} ", i );
}
The output:
0 1 2 3 4 5
Here's a solution with no LINQ:
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
// This assumes the numbers are sorted
var noRepeats = new List<int>();
int temp = numbers[0]; // Or .First() if using IEnumerable
var count = 1;
for(int i = 1; i < numbers.Length; i++) // Or foreach (var n in numbers.Skip(1)) if using IEnumerable
{
if (numbers[i] == temp) count++;
else
{
if(count == 1) noRepeats.Add(temp);
temp = numbers[i];
count = 1;
}
}
if(count == 1) noRepeats.Add(temp);
Console.WriteLine($"[{string.Join(separator: ",", values: numbers)}] -> [{string.Join(separator: ",", values: noRepeats)}]");
This prints:
[0,1,2,2,2,3,4,4,5] -> [0,1,3,5]
In .Net 2.0 I`m pretty sure about this solution:
public IEnumerable<T> Distinct<T>(IEnumerable<T> source)
{
List<T> uniques = new List<T>();
foreach (T item in source)
{
if (!uniques.Contains(item)) uniques.Add(item);
}
return uniques;
}

Categories