Removing almost-duplicates from nested list - c#

If I have the following sublists, how can I remove 'duplicates' so that I only have L1, L2 and L3 remaining? I don't mind which variant remains, as long as the duplicates are gone.
List<List<string>> mylist = new List<List<string>>();
List<string> L1 = new List<string> { "a", "b", "c" };
List<string> L2 = new List<string> { "d", "e", "f" };
List<string> L3 = new List<string> { "g", "h", "i" };
List<string> L4 = new List<string> { "c", "a", "b" };
List<string> L5 = new List<string> { "a", "c", "b" };
List<string> L6 = new List<string> { "f", "d", "e" };
It's worth mentioning that I'm removing the duplicates to improve performance in another part of my program, so anything too intensive would not be appropriate. Thanks!

you can use Linq by applying Distinct function with a custom comparer like the following code:
1 - Create Custom generic comparer for List<T>:
public class GenericComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.Count == y.Count && x.All(xx => y.Contains(xx));
}
public int GetHashCode(List<T> obj)
{
int hashCode = 0;
foreach(T str in obj)
{
hashCode ^= str.GetHashCode();
}
return hashCode;
}
}
2 - call Distinct function with StringListComparer like :
List<List<string>> mylist = new List<List<string>>()
{
new List<string> { "a", "b", "c" },
new List<string> { "d", "e", "f" },
new List<string> { "g", "h", "i" },
new List<string> { "c", "a", "b" },
new List<string> { "a", "c", "b" },
new List<string> { "f", "d", "e" },
};
var result = mylist.Distinct(new GenericComparer<string>()).ToList();
3 - Demo
foreach(List<string> strList in result)
{
Console.WriteLine(string.Join(",", strList));
}
4- Result
a,b,c
d,e,f
g,h,i
If you have a list of integer, you can call Distinct method like :
var result1 = mylist1.Distinct(new GenericComparer<int>()).ToList();
I hope this help you out.

Related

LINQ to get Distinct Count/Sort in List<List<string>>

I have a List<> that contains a List<string>, of which I need to determine the unique count from the List<string, and order by the frequency of the count.
Example:
"a","b","c"
"d","e","f"
"a","b"
"a", "b", "c"
"a", "b", "c"
"a","b"
This would output (rank / combination / frequency)
1 - "a", "b", "c" - 3
2 - "a", "b" - 2
3 "d", "e", "f" - 1
I can come up with a brute-force approach but can this be done more elegantly with LINQ? This isn't exactly a Cartesian approach from what I can tell.
Thanks.
You could write your own IEqualityComparer and use it with GroupBy.
public class StringArrayValueComparer : IEqualityComparer<List<string>>
{
public bool Equals(List<string> x, List<string> y)
=> x.SequenceEqual(y);
public int GetHashCode(List<string> obj)
=> obj.Aggregate(1, (current, s) => current * 31 + s.GetHashCode());
}
var list = new List<List<string>>(new[]
{
new List<string>(new [] { "a", "b", "c" }),
new List<string>(new [] { "d", "e", "f" }),
new List<string>(new [] { "a", "b" }),
new List<string>(new [] { "a", "b", "c" }),
new List<string>(new [] { "a", "b", "c" }),
new List<string>(new [] { "a", "b" })
});
var orderedList = list
.GroupBy(x => x, x => x, (x, enumerable) => new { Key = x, Count = enumerable.Count()}, new StringArrayValueComparer())
.OrderByDescending(x => x.Count)
.Select((x, index) => new { Rank = index + 1, Combination = x.Key, Frequency = x.Count });
foreach (var entry in orderedList)
{
Console.WriteLine($"{entry.Rank} - {string.Join(",", entry.Combination)} - {entry.Frequency}");
}
1 - a,b,c - 3
2 - a,b - 2
3 - d,e,f - 1

JQuery, Datatables and Ajax

I'm trying to dynamically load my datatable with an ASP.NET a web-method written in C#. The method seems to work well but nothing I try gets the datatable to respond properly.
Here's my code:
var oTable = $('table.datatable').dataTable({
"processing": true,
"serverSide": true,
"ajax": {
"url": "SearchForCustomers.aspx/GetUsers",
"type": "POST",
"contentType": "application/json; charset=utf-8",
"dataType": "json"
},
"columns": [{
"data": "A"
}, {
"data": "B"
}, {
"data": "C"
}, {
"data": "D"
}, {
"data": "E"
}, {
"data": "F"
}]
});
My ASP.NET web-method:
public class AA
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
[WebMethod]
public static string GetUsers()
{
/*List<UserAccount> listOfUserAccounts = UserAccount.GetUserAccounts(ApplicationConfiguration.ORDER_TYPES.DESC);
JavaScriptSerializer jSearializer = new JavaScriptSerializer();
return jSearializer.Serialize(listOfUserAccounts);*/
List<AA> list = new List<AA>();
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
JavaScriptSerializer jSearializer = new JavaScriptSerializer();
return jSearializer.Serialize(list);
}
The AA class was made up in order to test the functionally of the datatable. The datatable receives no rows at all.
Thanks in advance.
Why it is not working with webmethod
Because, when Jquery datable makes a post request, it does send some parameter to post method, in this case it is GetUsers. But since there is no input parameter for this function, it shows ajax error internal error 500 . Error message is - Invalid JSON primitive , if you search this, it says, if there is mismatch between jquery supplied param in post and webmethod ( in this case it is so), then this error occurs. I know, this input parameter is not required at binding time, but still datatable ajax sends that for binding time, and those parameter are helpful for sorting, paging etc. Following is the screenshot,that shows POST params.
How to solve this
Move those methods to ashx hanlder, this way parameter ( such as sorting, searching etc..) will be captured by context.Request.Form ( this might not be required at binding time - this is your case).
But still, you need to modify supplied code, you need to wrap List<AA> to data and also include totalRecord, else jquery datatable shows error. Following is the code that i have tried and it is working.
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/json";
List<AA> list = new List<AA>();
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
list.Add(new AA { A = "a", B = "b", C = "c", D = "d", E = "e", F = "f" });
JavaScriptSerializer jSearializer = new JavaScriptSerializer();
var result = new { data = list, recordsTotal = 8 };
context.Response.Write(jSearializer.Serialize(result));
}

How to find if an element of a list is in another list and the name of element?

First I want to know if at least one element in a first list can be found in a second list.
List<string> list1 = new[] { "A", "C", "F", "H", "I" };
List<string> list2 = new[] { "B", "D", "F", "G", "L" };
I am using below code to do this -
bool isFound = list1.Intersect(list2).Any();
But I want to know which element is that. Like in above case it is 'F'
What is the best way to do this?
You just use Intersect only:
var result = list1.Intersect(list2);
Try:
List<string> list1 = new List<string> { "A", "C", "F", "H", "I" };
List<string> list2 = new List<string> { "B", "D", "F", "G", "L" };
String sel = list1.Intersect(list2).FirstOrDefault()??"";
Console.WriteLine(sel);
Try my Demo
You can use Enumerable.Intersect method only, you don't need to use Any in your case.
Produces the set intersection of two sequences.
List<string> list1 = new List<string>(){ "A", "C", "F", "H", "I" };
List<string> list2 = new List<string>(){ "B", "D", "F", "G", "L" };
var intersect = list1.Intersect(list2);
foreach (var i in intersect)
{
Console.WriteLine(i);
}
Output will be;
F
Here is a DEMO.
Instead of bool variable You can take another list variable like:
List<string> list3 Variable to get list of items which are forund in second list and assign the result to list3
List<string> list3= list1.Intersect(list2).ToList();

String Array. Select

I have the following string arrays:
var array1 = new String[] { "A", "B", "C", "D" }
var array2 = new String[] { "B", "D" }
I need to do the following:
1) Find the item in array2 which appears firts in array1 (In this case is B);
2) Get the item in (1) and all the others which appear after it in array1.
So in this case I would get:
var array3 = new String[] { "B", "C", "D" }
I was trying to do it, in one step, using a lambda expression.
Is this possible?
var array3 = array1.SkipWhile(x => !array2.Contains(x)).ToArray();

Need a little help with SelectMany

Suppose, I have an IEnumerable<Tuple<string, object>> and that I want to replace for each element of the enumeration the first element by a list of (several) other elements:
Original enumerable: { { "a", obj1 }, { "b", obj2 } }
First-element replacement: a -> { "c", "d" }, b -> { "e", "f", "g" }
Result : { { "c", obj1 }, { "d", obj1 }, { "e", obj2 }, { "f" , obj2 }, { "g" , obj2 } }
How can I accomplish this with SelectMany in a better way than
enumerable.SelectMany(item => ReplacementFunction(item.Item1).Select(newItem =>
new Tuple<string, object>(newItem, item.Item2)))
Well, I'd probably use a query expression instead:
var query = from tuple in enumerable
from replacement in ReplacementFunction(tuple.Item1)
select Tuple.Create(replacement, tuple.Item2);
But that's basically the same thing...

Categories

Resources