Need a little help with SelectMany - c#

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...

Related

Removing almost-duplicates from nested list

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.

Adding multiple values on list

Is it possible to add multiple items into list or adding a list of values into a list.
here is my current pseudo code to do it:
List<string> myList = new List<string>();
myList.add("a","b","c","d","e","f","g");
myList.add("h","i","j","k","l","m","n");
myList.add("a1","a2","a3");
and my expected result is:
[["a","b","c","d","e","f","g"], ["h","i","j","k","l","m","n"], ["a1","a2","a3"]]
Any suggestions/comments TIA.
What you are asking for is a List<List<string>>. There are probably better structures for storing your data but since you haven't given any context, you can do this:
var myList = new List<List<string>>();
And add items like this:
myList.Add(new List<string> { "a", "b", "c", "d", "e", "f", "g" });
myList.Add(new List<string> { "h", "i", "j", "k", "l", "m", "n" });
myList.Add(new List<string> { "a1", "a2", "a3" });
Or in one piece of code using a collection initialiser:
var myList = new List<List<string>>
{
new List<string> { "a", "b", "c", "d", "e", "f", "g" },
new List<string> { "h", "i", "j", "k", "l", "m", "n" },
new List<string> { "a1", "a2", "a3" }
};
Should be as easy as
var myList = new List<List<string>>()
{
new List<string> { "a", "b", "c", "d", "e", "f", "g" },
new List<string> { "h", "i", "j", "k", "l", "m", "n" },
new List<string> { "a1", "a2", "a3" },
};
// OR
var myarray = new[]
{
new[] { "a", "b", "c", "d", "e", "f", "g" },
new[] { "h", "i", "j", "k", "l", "m", "n" },
new[] { "a1", "a2", "a3" },
};
Additional Resources
Object and Collection Initializers (C# Programming Guide)
C# lets you instantiate an object or collection and perform member
assignments in a single statement.
Collection initializers
Collection initializers let you specify one or more element
initializers when you initialize a collection type that implements
IEnumerable and has Add with the appropriate signature as an instance
method or an extension method. The element initializers can be a
simple value, an expression, or an object initializer. By using a
collection initializer, you do not have to specify multiple calls; the
compiler adds the calls automatically.

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

Compare two List<string> using LINQ in C#

What is the best way to compare two lists based on values, order and the number of values. So all of the lists below should be different.
var list1 = new List<string> { "1", "2" };
var list2 = new List<string> { "2", "1" };
var list3 = new List<string> { "1", "2", "3" };
How about using SequenceEqual.
See http://ideone.com/yZeYRh
var a = new [] { "1", "2", "3" };
var b = new [] { "1", "2" };
var c = new [] { "2", "1" };
Console.WriteLine(a.SequenceEqual(b)); // false
Console.WriteLine(a.SequenceEqual(c)); // false
Console.WriteLine(c.SequenceEqual(b)); // false
It comes from the namespace System.Linq and can be used on any IEnumerable.
You can also pass it an IEqualityComparer to for example also do:
var d = new [] { "a", "B" };
var e = new [] { "A", "b" };
Console.WriteLine(d.SequenceEqual(e, StringComparer.OrdinalIgnoreCase)); // true
I like Zip for this, but you still need to manually compare Count.
lista.Count() ==listb.Count() && lista.Zip(listb, Equals).All(a=>a);

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

Categories

Resources