I would like to know if there's a LINQ operator to do this:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var combined = new [] { one, two };
var result = Operator(combined);
Console.WriteLine(result.Should().BeEquivalentTo(new [] { "A", "A", "B", "B", "C", "C", null, "D" }));
If short, it should act like if every sequence was a row in a matrix. And after that, it should:
Transpose the matrix (rotate it)
It should push every "cell" in the matrix, returning the corresponding item, or default if the cell is empty.
I mean, graphically:
A, B, C
A, B, C, D
<Transpose>
A, A
B, B
C, C
D
result => A, A, B, B, C, C, D, null
NOTICE
Operator should work on IEnumerable<IEnumerable<T>>
As you can see, the Operator I'm interested in, uses combined, so it accepts should IEnumerable<IEnumerable<T>> (like SelectMany).
It's a bit hard keeping up with your changing specs. Originally, it was a pair of string arrays. I changed that to be a pair of arrays of T in my answer.
Then you wrote in a comment that "oh, no, I meant N sequences". Finally, after reading that, I noticed that you'd updated your question to ask about N collections expressed as IEnumerable<T>.
In the mean time, I pointed out that my original answer would work well for N arrays with minimal change. So, here goes:
For N Arrays
I use the params keyword to remove the need for your combined variable. The params keyword will compose some or all of the parameters of a method into an array.
Here's a method that can take N arrays:
public static IEnumerable<T> KnitArrays<T>(params T[][] arrays)
{
var maxLen = (from array in arrays select array.Length).Max();
for (var i = 0; i < maxLen; i++)
{
foreach( var array in arrays)
{
yield return array.Length > i ? array[i] : default(T);
}
}
}
It's pretty much the same logic as the original answer. The test code looks the same as well:
var one = new[] { "A1", "B1", "C1" };
var two = new[] { "A2", "B2", "C2", "D2" };
var three = new[] { "A3", "B3" };
var knittedArray = KnitArrays(one, two, three);
List<string> result = knittedArray.ToList();
WriteCollectionContents(result);
Where WriteCollectionContents spits out the contents of the collection. In this case:
"A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", null, null, "D2", null,
For N Lists and/or Arrays
It turns out that the same basic code can work with IList<T>, i.e., for both List<T> and T[]:
public static IEnumerable<T> KnitILists<T>(params IList<T>[] ilists)
{
var maxLen = (from ilist in ilists select ilist.Count).Max();
for (var i = 0; i < maxLen; i++)
{
foreach (var ilist in ilists)
{
yield return ilist.Count > i ? ilist[i] : default(T);
}
}
}
The test code for this also looks pretty similar - though note the mix or arrays and lists:
var one = new[] { "A1", "B1", "C1" };
var two = new[] { "A2", "B2", "C2", "D2" };
var list3 = new List<string> { "A3", "B3" };
var knittedLists = KnitILists(one, two, list3);
result = knittedLists.ToList();
WriteCollectionContents(result);
With exactly the same result:
"A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", null, null, "D2", null,
The reason it works with IList<T> is that that interface has a Count property and an Item indexer. If you go to ICollection<T> the Count property stays, but you lose the Item indexer.
Once you get to IEnumerable<T>, both the Count property and the Item indexer are gone. The only thing you can do with an IEnumerable is to iterate through it. As a result, the logic needs to be very different.
I might get around to coming up with a solution. However, it will likely look very similar to #gertarnold's answer.
I'm looking foreword to your upcoming comment about how you really meant for this to work with multi-dimensional arrays as well.
Original answer follows
How about something like this:
public static IEnumerable<T> KnitArrays<T>(T[] first, T[] second)
{
var maxLen = Math.Max(first.Length, second.Length);
for (var i = 0; i < maxLen; i++)
{
yield return first.Length > i ? first[i] : default(T);
yield return second.Length > i ? second[i] : default(T);
}
}
Testing this with:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var knittedArray = KnitArrays(one, two);
List<string> result = knittedArray.ToList();
yields a list that looks like what you are asking. Note that I just return a non-materialized IEnumerable since you were asking about LINQ.
To make the result independent of the number of arrays the function should loop trough all arrays and keep returning until all enumerations are exhausted:
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
var enumerators = source.Select(e => e.GetEnumerator()).ToArray();
try
{
var next = false;
do
{
var results = enumerators.Select(enr =>
{
if (enr.MoveNext())
{
return enr.Current;
}
return default;
}).ToList();
next = results.Any(e => !Equals(default, e));
if (next)
{
yield return results;
}
}
while (next);
}
finally
{
Array.ForEach(enumerators, e => e.Dispose());
}
}
Now you can use any number of arrays:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var three = new[] { "U", "V","W", "X", "Y", "Z" };
var combined = new[] { one, three, two };
var result = combined.Transpose().SelectMany(e => e).ToList();
This will result in
"A","U","A","B","V","B","C","W","C",null,"X","D",null,"Y",null,null,"Z",null
Filtering the null values is trivial.
(Courtesy this answer for the basic idea, but only working for arrays of equal length).
try this
var result = Enumerable.Range(0, Math.Max(one.Count(), two.Count()))
.SelectMany(n => new[] { one.ElementAtOrDefault(n), two.ElementAtOrDefault(n) });
result
["A","A","B","B","C","C",null,"D"]
Related
I basically want to know if a string array from one list exists in another list of string array
So for example:
List 1:
{"A", "R1"}
{"A", "R2"}
List 2:
{"A", "R1"}
{"B", "R1"}
{"B", "R2"}
Then If I loop in List 1 to check whether it exists in List 2 the results will be:
true
false
I want to do it in LINQ if possilbe
You can use
Any and SequenceEqual
for this.
using System.Collections.Generic;
List<string[]> testSet = new List<string[]>
{
new string[] { "A", "R1" },
new string[] { "A", "R2" }
};
List<string[]> resultSet = new List<string[]>
{
new string[] { "A", "R1" },
new string[] { "B", "R1" },
new string[] { "B", "R2" }
};
// Checks if the value is found anywhere in the list
bool IsArrayInList(string[] value, List<string[]> list)
{
return list.Any(value.SequenceEqual);
}
foreach (var val in testSet)
{
Console.WriteLine(IsArrayInList(val,resultSet));
}
Console.ReadLine();
I would suggest a combination of .Any() and .SequenceEqual() or .All()
Example:
var list1 = new string[][]
{
new string[] { "A", "R1" },
new string[] { "A", "R2" },
};
var list2 = new string[][]
{
new string[] { "A", "R1"},
new string[] { "B", "R1"},
new string[] { "B", "R2"},
};
var itemToFind = list1.First();
// Option 1
var isInList2 = list2.Any(i => i.SequenceEqual(itemToFind));
// Option 2
var isInList2Option2 = list2.Any(item => item.All(innerItem => itemToFind.Contains(innerItem)));
As-needed, you can improve these to account for ordering, case-insensitivity, exact number of arguments, etc...
Option 1 will find any matches where the inner sequence is in the same order, same-casing as what you are looking for.
Option 2 will find any matches where the inner sequence contains all of the values of the sequence you are checking for.
Hopefully this points you in the right direction at least.
I have a list of strings, which is ordered with a particular method :
list1 : { "E", "C", "B", "A"};
Now I want to check other arrays that if it was ordered according to list1, then it is correct.
for example :
array: { "A", "C", "E", "B" } //false - not ordered according to list1
array: { "E", "B", "C" } //false - not ordered according to list1
array: { "C", "A"} //true- ordered according to list1
Function codes:
List<string> list1 = new List<string> { "E", "C", "B", "A"};
public static bool IsSorted(string[] array)
{
for (int i = 0; i < array.Length; i++)
{
if () //Your opinion
{
return false;
}
}
return true;
}
I think it's easy using Lists instead of array
Here is an example :
List<int> list1 = new List<int>();
list1.Add(1);
list1.Add(2);
list1.Add(3);
List<int> list2 = new List<int>();
list2.Add(2);
list2.Add(3);
Console.WriteLine( list1.Intersect(list2).SequenceEqual(list2)); // Will return true
Posted an example about int variables according to your example, You can use what ever type you want
UPDATE : It works well with arrays too ( Thanks to #Matthew Watson)
int[] arr1 = { 1, 2, 3 };
int[] arr2 = { 2, 3 };
Console.WriteLine( arr1.Intersect(arr2).SequenceEqual(arr2)); // will return true
For the case <= ({ "E", "E" } is true) it is quite simple:
static List<string> list1 = new List<string> { "E", "C", "B", "A" };
// Uses a <= algorithm, so "E", "E" is true
public static bool IsSorted(IEnumerable<string> enu)
{
// index of last letter used in list1
int lastIndex = 0;
foreach (string str in enu)
{
// Start searching from the last index found
int index = list1.IndexOf(str, lastIndex);
// index == -1 means not found
if (index == -1)
{
return false;
}
lastIndex = index;
}
return true;
}
Comments in code.
if you want a <, so that { "E", "E" } is false:
// Uses a < algorithm, so "E", "E" is false
public static bool IsSorted(IEnumerable<string> enu)
{
// Note that we have a +1 in the IndexOf to balance the -1 here
int lastIndex = -1;
foreach (string str in enu)
{
// Start searching from the last index found + 1
int index = list1.IndexOf(str, lastIndex + 1);
// index == -1 means not found
if (index == -1)
{
return false;
}
lastIndex = index;
}
return true;
}
You can use two LINQ methods for that: Intersect to get the items that are common to both lists; and then SequenceEqual to check if both lists have the same items in the same order. So:
listToCheck.Intersect(list1).SequenceEqual(listToCheck)
I have two IEnumerables:
IEnumerable<string> first = ...
IEnumerable<string> second = ...
I want to create a second IEnumerable<string> that is the concatenation of each element of each IEnumerable.
For example:
IEnumerable<string> first = new [] {"a", "b"};
IEnumerable<string> second = new [] {"c", "d"};
foreach (string one in first)
{
foreach (string two in second)
{
yield return string.Format("{0} {1}", one, two);
}
}
This would produce:
"a c"; "a d"; "b c"; "b d";
The problem is, sometimes one of the two IEnumerables is empty:
IEnumerable<string> first = new string[0];
IEnumerable<string> second = new [] {"c", "d"};
In this case, the nested foreach construct never reaches the yield return statement. When either IEnumerable is empty, I would like the result to just be the list of the non-empty IEnumerable.
How can I produce the combinations I am looking for?
EDIT:
In reality, I have three different IEnumerables I am trying to combine, so adding if conditions for every possible permutation of empty IEnumerable seems bad. If that's the only way, then I guess I'll have to do it that way.
You can simply check that first enumerable is not empty:
IEnumerable<string> first = new [] {"a", "b"};
IEnumerable<string> second = new [] {"c", "d"};
var firstList = first.ToList();
if (!firstList.Any()) {
return second;
}
foreach (string one in firstList)
{
foreach (string two in second)
{
yield return string.Format("{0} {1}", one, two);
}
}
To eliminate double IEnumerable evaluation in positive cases just convert first enumerable to list
Simply use Enumerable.DefaultIfEmpty() to enumerate collection even if there is no items.
IEnumerable<string> first = new string[0];
IEnumerable<string> second = new[] { "a", "b" };
IEnumerable<string> third = new[] { "c", null, "d" };
var permutations =
from one in first.DefaultIfEmpty()
from two in second.DefaultIfEmpty()
from three in third.DefaultIfEmpty()
select String.Join(" ", NotEmpty(one, two, three));
Note: I have used String.Join to join items which are not null or empty and method to select non-empty items to be joined (you can inline this code if you don't want to have a separate method):
private static IEnumerable<string> NotEmpty(params string[] items)
{
return items.Where(s => !String.IsNullOrEmpty(s));
}
Output for sample above is
[ "a c", "a", "a d", "b c", "b", "b d" ]
For two collections and foreach loops (though I would prefere LINQ as above):
IEnumerable<string> first = new[] { "a", "b" };
IEnumerable<string> second = new string[0];
foreach(var one in first.DefaultIfEmpty())
{
foreach(var two in second.DefaultIfEmpty())
yield return $"{one} {two}".Trim(); // with two items simple Trim() can be used
}
Output:
[ "a", "b" ]
Your current approach should work until any of the collections is empty. If this is the case you need some check in front:
if(!first.Any())
foreach(var e in second) yield return e;
else if(!second.Any())
foreach(var e in first) yield return e;
foreach (string one in first)
{
foreach (string two in second)
{
yield return string.Format("{0} {1}", one, two);
}
}
However you should consider making an immediate execution using ToList in front to avoid multiple iterations of the same collection.
Assuming you're output for case :
IEnumerable<string> first = new string[0];
IEnumerable<string> second = new [] {"c", "d"};
would be :
c
d
This would work :
var query = from x in first.Any() ? first : new [] { "" }
from y in second.Any() ? second : new[] { "" }
select x + y;
Less code , easier to maintain and debug !
Edit : If you have any other IEnumerable is just 1 extra line per IEnumerable ( includes the check )
var query = from x in first.Any() ? first : new [] { "" }
from y in second.Any() ? second : new[] { "" }
from z in third.Any() ? third : new[] { "" }
select x + y + z;
Edit 2 : you can just add the spaces at the end :
select (x + y + z).Aggregate(string.Empty, (c, i) => c + i + ' ');
If you have more than a couple lists, you can setup a recursive iterator. You'll want to be mindful of the stack, and I think the string concatenation is less than ideal, and passing lists of lists is rather clunky, but this should get you started.
using System;
using System.Collections.Generic;
using System.Linq;
namespace en
{
class Program
{
static void Main(string[] args)
{
// three sample lists, for demonstration purposes.
var a = new List<string>() { "a", "b", "c" };
var b = new List<string>() { "1", "2", "3" };
var c = new List<string>() { "i", "ii", "iii" };
// the function needs everything in one argument, so create a list of the lists.
var lists = new List<List<string>>() { a, b, c };
var en = DoStuff(lists).GetEnumerator();
while (en.MoveNext())
{
Console.WriteLine(en.Current);
}
}
// This is the internal function. I only made it private because the "prefix" variable
// is mostly for internal use, but there might be a use case for exposing that ...
private static IEnumerable<String> DoStuffRecursive(IEnumerable<String> prefix, IEnumerable<IEnumerable<String>> lists)
{
// start with a sanity check
if (object.ReferenceEquals(null, lists) || lists.Count() == 0)
{
yield return String.Empty;
}
// Figure out how far along iteration is
var len = lists.Count();
// down to one list. This is the exit point of the recursive function.
if (len == 1)
{
// Grab the final list from the parameter and iterate over the values.
// Create the final string to be returned here.
var currentList = lists.First();
foreach (var item in currentList)
{
var result = prefix.ToList();
result.Add(item);
yield return String.Join(" ", result);
}
}
else
{
// Split the parameter. Take the first list from the parameter and
// separate it from the remaining lists. Those will be handled
// in deeper calls.
var currentList = lists.First();
var remainingLists = lists.Skip(1);
foreach (var item in currentList)
{
var iterationPrefix = prefix.ToList();
iterationPrefix.Add(item);
// here's where the magic happens. You can't return a recursive function
// call, but you can return the results from a recursive function call.
// http://stackoverflow.com/a/2055944/1462295
foreach (var x in DoStuffRecursive(iterationPrefix, remainingLists))
{
yield return x;
}
}
}
}
// public function. Only difference from the private function is the prefix is implied.
public static IEnumerable<String> DoStuff(IEnumerable<IEnumerable<String>> lists)
{
return DoStuffRecursive(new List<String>(), lists);
}
}
}
console output:
a 1 i
a 1 ii
a 1 iii
a 2 i
a 2 ii
a 2 iii
a 3 i
a 3 ii
a 3 iii
b 1 i
b 1 ii
b 1 iii
b 2 i
b 2 ii
b 2 iii
b 3 i
b 3 ii
b 3 iii
c 1 i
c 1 ii
c 1 iii
c 2 i
c 2 ii
c 2 iii
c 3 i
c 3 ii
c 3 iii
I want to compare elements inside a single List in C#. I need to check whether same data is there in list or not . Can anybody help me with this?
You can try this, for example:
var collection = new List<double>(new double[] { 10, 20, 11, 10, 20, 44 });
var info = collection.GroupBy(e => e).ToDictionary(e => e.Key, e => e.Count());
Here info contain a double value as a key and number of this number in collection as value.
And this construction you can use with any type of List elements.
You could use the LINQ extention methods
here is an example of LINQ comparing lists:
list<string> arr1 = new list<string>(){ "A", "b", "C," };
list<string> arr2 = new list<string>(){ "A", "b", "C," };
Compare the above arrays with the SequentialEqual() Method
bool result = arr3.SequentialEqual(arr2);
The Boolean result will contain true as the items in both lists are equal
Hope this helps
If you just want to know if there is more than one item in the list has the same value you can use this function..
public bool HasSameData<T>(List<T> myList)
{
return myList.Distinct().Count() != myList.Count();
}
note that this will work with any type.
void Main()
{
var myList = new List<int> {1,2,3,4,5,6,7,8,9};
var myList2 = new List<int> {1,1,3,4,5,6,7,8,9};
Console.WriteLine(HasSameData(myList));
Console.WriteLine(HasSameData(myList2));
var myList3 = new List<String> {"hello","world","foo","bar"};
var myList4 = new List<String> {"hello","foo","foo","bar"};
Console.WriteLine(HasSameData(myList3));
Console.WriteLine(HasSameData(myList4));
Console.ReadLine();
}
OUTPUT:
False
True
False
True
Dear all , this is something like my previous question How to get moving combination from two List<String> in C#?
I'm having a masterlist and two childlist like below
List<String> MasterList = new List<string> { "A", "B", "C", "D", "E" };
List<String> ListOne = new List<string> { "A", "B", "C" };
List<String> ListTwo = new List<String> { "B", "D" };
I just need to get the running combination from the above list for that i'm using like(previous question's answer(Thanks Danny Chen))
List<String> Result = new List<string>();
Result = ListOne.SelectMany((a, indexA) => ListTwo
.Where((b, indexB) => ListTwo
.Contains(a) ? !b.Equals(a) && indexB > indexA :
!b.Equals(a)).Select(b => string.Format("{0}-{1}", a, b))).ToList();
so the Result list will contain
"A-B"
"A-D"
"B-D"
"C-B"
"C-D"
Now my problem is the sorting issue
In the above result the fourth entry is C-B but it should be B-C. Because in the MasterList the C is after B.
How to do this in my existing linq .
Please help me to do this.
Not really clear on the exact requirement here, so does the MasterList dictate which of the two items should appear first? What about the order of the X1-X2 list? i.e. should B-C appear before B-D because C appears before D in the MasterList?
Anyway, here's something that produces the result you've asked for so far:
List<String> MasterList = new List<string> { "A", "B", "C", "D", "E" };
List<String> ListOne = new List<string> { "A", "B", "C" };
List<String> ListTwo = new List<String> { "B", "D" };
ListOne.SelectMany(i =>
ListTwo.Where(i2 => i != i2)
.Select(i2 =>
{
if (MasterList.IndexOf(i) < MasterList.IndexOf(i2))
return string.Format("{0}-{1}", i, i2);
else
return string.Format("{0}-{1}", i2, i);
}
));
outputs:
A-B
A-D
B-D
B-C
C-D