Skip foreach X positions - c#

I want skip my in foreach. For example:
foreach(Times t in timeList)
{
if(t.Time == 20)
{
timeList.Skip(3);
}
}
I want "jump" 3 positions in my list.. If, in my if block t.Id = 10 after skip I want get t.Id = 13

How about this? If you use a for loop then you can just step the index forward as needed:
for (var x = 0; x < timeList.Length; x++)
{
if (timeList[x].Time == 20)
{
// option 1
x += 2; // 'x++' in the for loop will +1,
// we are adding +2 more to make it 3?
// option 2
// x += 3; // just add 3!
}
}

You can't modify an enumerable in-flight, as it were, like you could the index of a for loop; you must account for it up front. Fortunately there are several way to do this.
Here's one:
foreach(Times t in timeList.Where(t => t.Time < 20 || t.Time > 22))
{
}
There's also the .Skip() option, but to use it you must break the list into two separate enumerables and then rejoin them:
var times1 = timeList.TakeWhile(t => t.Time != 20);
var times2 = timeList.SkipeWhile(t => t.Time != 20).Skip(3);
foreach(var t in times1.Concat(times2))
{
}
But that's not exactly efficient, as it requires iterating over the first part of the sequence twice (and won't work at all for Read Once -style sequences). To fix this, you can make a custom enumerator:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, int SkipCount)
{
bool triggered = false;
int SkipsRemaining = 0;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
SkipsRemaining = SkipCount;
}
if (triggered)
{
SkipsRemaining--;
if (SkipsRemaining == 0) triggered = false;
}
else
{
yield return e.Current;
}
}
}
Then you could use it like this:
foreach(Times t in timeList.SkipAt(t => t.Times == 20, 3))
{
}
But again: you still need to decide about this up front, rather than inside the loop body.
For fun, I felt like adding an overload that uses another predicate to tell the enumerator when to resume:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, Predicate<T> ResumeTrigger)
{
bool triggered = false;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
}
if (triggered)
{
if (ResumeTrigger(e.Current)) triggered = false;
}
else
{
yield return e.Current;
}
}
}

You can use continue with some simple variables.
int skipCount = 0;
bool skip = false;
foreach (var x in myList)
{
if (skipCount == 3)
{
skip = false;
skipCount = 0;
}
if (x.time == 20)
{
skip = true;
skipCount = 0;
}
if (skip)
{
skipCount++;
continue;
}
// here you do whatever you don't want to skip
}
Or if you can use a for-loop, increase the index like this:
for (int i = 0; i < times.Count)
{
if (times[i].time == 20)
{
i += 2; // 2 + 1 loop increment
continue;
}
// here you do whatever you don't want to skip
}

Related

Queue move item back to the end

I have a System.Collection.Generic.Queue<int> with following sample code
Queue<int> iq = new Queue<int>();
iq.Enqueue(1); // 1
iq.Enqueue(2); // 1 2
iq.Enqueue(3); // 1 2 3
//move 1 to the end of the line here
int i = iq.Dequeue(); // 2 3
I want to move the value (access by value) 1 back to the end of the line so that the result is 2 and 1 would be the last dequeueable value.
Any idea? Is there something like iq.MoveToLast(1) ?
If you want to Remove / Add item by its value, you can use List<T> instead of Queue<T>:
List<int> id = ...
int itemToMove = 2;
int index = id.IndexOf(itemToMove);
// If we have item found we should put it at the end
if (index >= 0) {
id.Add(id[index]);
id.RemoveAt(index);
}
If you have to use Queue<T> you can create a temporal List<T>:
Queue<int> iq = ...
int itemToMove = 2;
// Create temporal list
var list = iq.ToList();
// process items in it
int index = list.IndexOf(itemToMove);
if (index >= 0) {
list.Add(list[index]);
list.RemoveAt(index);
}
// enqueue items back into queue in the desired order
iq.Clear();
foreach (var item in list)
iq.Enqueue(item);
Finally, you can implement an extension method:
public static partial class QueueExtensions {
public static void MoveToLast<T>(this Queue<int> queue, T itemToMove) {
if (null == queue)
throw new ArgumentNullException(nameof(queue));
var list = queue.ToList();
int index = list.IndexOf(itemToMove);
if (index < 0)
return; // Nothing to do
list.Add(list[index]);
list.RemoveAt(index);
queue.Clear();
foreach (var item in list)
queue.Enqueue(item);
}
}
Then you can put
iq.MoveToLast(1);
Just try:
queue.Enqueue(queue.Dequeue());
You can't Remove elements from Queue by using methods other than Dequeue.
Here's an approach which just manipulates the queue:
public static void MoveElementToBack<T>(Queue<T> queue, T elementToMove)
{
T item = default;
bool found = false;
for (int i = 0, n = queue.Count; i < n; ++i)
{
var current = queue.Dequeue();
if (!found && current.Equals(elementToMove))
{
item = current;
found = true;
}
else
{
queue.Enqueue(current);
}
}
if (found)
queue.Enqueue(item);
}
This is always an O(N) operation, but it only makes one pass through the queue.

Merging two lists which are already sorted in c#

So i have two sorted lists with deliverable's and I want to Merge them. I never did this operation before and i can not really make it work. You can see method below that i wrote. I can not figure out while statement because it fires exception all the time. I dont know what to do...
public void MergeLists(List<Deliverable> a, List<Deliverable> b)
{
int index1 = 0;
int index2 = 0;
while (a.Count() >= index1 || b.Count() >= index2)
{
if (a[index1].ID> b[index2].ID)
{
FinalDeliverables.Add(a[index1]);
index1++;
}
else if (a[index1].ID < b[index2].ID)
{
FinalDeliverables.Add(a[index2]);
index2++;
}
else if (a[index1].ID == b[index2].ID)
{
FinalDeliverables.Add(a[index1]);
FinalDeliverables.Add(a[index2]);
index1++;
index2++;
}
}
}
I believe that the exceptions you are getting are coming from null pointers. This would occur if, for example, you already reached the end of one of the lists, yet your while loop is still trying to compare values. One workaround to this is to simply add a check before the if statements to see if one (or both) of the ends of the lists have been reached. If so, then simply add the remainder of the items from the other list.
public void MergeLists(List<Deliverable> a, List<Deliverable> b)
{
int index1 = 0;
int index2 = 0;
while (true)
{
// if the end of the 'a' list has been reached, then add
// everything from the 'b' list and break from the loop
if (index1 >= a.Count()) {
for (int i=index2; i < b.Count(); ++i) {
FinalDeliverables.Add(b[i]);
}
break;
}
// if the end of the 'b' list has been reached, then add
// everything from the 'a' list and break from the loop
if (index2 >= b.Count()) {
for (int i=index1; i < a.Count(); ++i) {
FinalDeliverables.Add(a[i]);
}
break;
}
if (a[index1].ID > b[index2].ID)
{
FinalDeliverables.Add(a[index1]);
index1++;
}
else if (a[index1].ID < b[index2].ID)
{
FinalDeliverables.Add(a[index2]);
index2++;
}
else if (a[index1].ID == b[index2].ID)
{
FinalDeliverables.Add(a[index1]);
FinalDeliverables.Add(a[index2]);
index1++;
index2++;
}
}
}
Note that a side effect of this refactor is that your original while loop no longer has to check boundaries. Instead, the loop will be terminated when one of the lists has been exhausted.
Also note that this solution assumes that your input lists are sorted in descending order.
You can use the LINQ Extension methods for this purpose, The Method signature for MergeLists will be like the following:
public void MergeLists(List<Deliverable> a, List<Deliverable> b)
{
var finalList = a.Concat(b);
List<Deliverable> FinalSortedList = finalList.OrderBy(x => x.ID).ToList();
}
Or else you can modify your own method as like the following: Before that Let me assume the following, The Count of elements in the Input list a will always be Greater than that of b. SO what you need to do is Check the count of elements before calling the method as well. So the call will be like the following:
if(a.Count>b.Count)
MergeLists(a,b);
else
MergeLists(b,a);
You mentioned that the two inputs ware sorted, Let me assume those lists are sorted in ascending order. Now consider the following code:
public void MergeLists(List<Deliverable> a, List<Deliverable> b)
{
int largeArrayCount = a.Count;
int currentBIndex = 0;
List<Deliverable> FinalResult = new List<Deliverable>();
for (int i = 0; i < largeArrayCount; i++)
{
if (i < b.Count)
{
if (a[i].ID >= b[i].ID)
{
// Add All elements of B Which is smaller than current element of A
while (a[i].ID <= b[currentBIndex].ID)
{
FinalResult.Add(b[currentBIndex++]);
}
}
else
{
FinalResult.Add(a[i]);
}
}
else
{
// No more elements in b so no need for checking
FinalResult.Add(a[i]);
}
}
}

Performance impact due to Nested forEach loop upto 4 levels

I have a very unique situation in which i am generating a file for which i have to use nested loops.
So for the current file i have 4 level of nested foreach (). when the data is less its performance is ok ok type still not good but when data start growing the loop grows exponentially due to nested.
Hence it is taking lot of time. Please suggest me some alternative or how can i optimize my code.
Use case:
The file i am trying to print say is having a blue print of the structure which have these nested loop, so i had to go with nesting .
Eg:
Member Details (Level 1)
Health Coverage (Level 2)
Provider Information (Level 3)
BeneFits (Level 4)
So Member details which can have multiple Health Coverage in which each health Coverage can have multiple Provider in which each Provider can have multiple benefits.
hope this help with my situation in a real time example
Level1
foreach()
{
//do some stuff
//writer.writeline();
level2
foreach()
{
//do some stuff
//writer.writeline();
level3
foreach()
{
//do some stuff
//writer.writeline();
level4
foreach()
{
//do some stuff
//writer.writeline();
}
}
}
}
Code
In the method used below writeWholeLine() , it again contain 3 nested for each loop, was not able to post the code here due to limit of character of body
private string TransactionsGeneration(StreamWriter writer, string line, int maximumCount)
{
#region Re-Generation
TransactionCounter = 0;
foreach (DataRow memRow in MemberTblMaster.Rows)
{
TransactionCounter++;
line = string.Empty; //begin of a new Transaction
//Counter
TotalLines = 0;
ST_SE_UniqueCode = 0;
// Fill the dataset based on the member id
MemberID = Convert.ToString(memRow[MEMBER_ID]).Trim();
HealthCoverageTbl = HealthCoverageTblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
Associations834Tbl = Associations834TblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
AddressTbl = AddressTblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
GenNameInfoTbl = GenNameInfoTblMaster.AsEnumerable().Where(x => x.Field<string>(Gen_Name_ID).Trim() == memRow[Sponsor_ID].ToString().Trim() ||
x.Field<string>(Gen_Name_ID).Trim() == memRow[Payer_ID].ToString().Trim() ||
x.Field<string>(Gen_Name_ID).Trim() == memRow[TPA_Broker_ID].ToString().Trim()
);
ContactTbl = ContactTblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
GenReferenceTbl = GenReferenceTblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
MemberTbl = MemberTblMaster.AsEnumerable().Where(x => x.Field<string>(MEMBER_ID).Trim() == MemberID);
// Based on Health Coverage
//Provider , COB
var loopLevel1 = (from row in LoopOrder.AsEnumerable()
where row.Field<int>(HIERARCHY_LEVEL) == 1
&& !Header.Contains(row.Field<string>(LOOP_ID).Trim())
&& !Footer.Contains(row.Field<string>(LOOP_ID).Trim())
select row);
foreach (DataRow parentLoop in loopLevel1)
{
//Level 1
//TODO : Need to implement the parent loop functionality
ParentLoop = Convert.ToString(parentLoop[PARENT_LOOP]);
string loopIDofLoopOrder = parentLoop[LOOP_ID].ToString();
LoopID = loopIDofLoopOrder;
var resultLevel1 = (from row in ValidationElementAttribute.AsEnumerable()
where row.Field<string>(LoopIdSegment).Trim() == loopIDofLoopOrder
select row);
if (resultLevel1.Any())
{
int maxCount1;
if (String.IsNullOrEmpty(Convert.ToString(parentLoop[Repeat_max])))
maxCount1 = maximumCount; //Max_Repitition = NULL means infinite number of repititions allowed; no upper cap
else
maxCount1 = Convert.ToInt32(parentLoop[Repeat_max]);
for (int i = 0; i < maxCount1; i++) //until all the repititions are covered, keep repeating the same loop, else change the parent loop
{
SkipLine = false;
WriteWholeLine(line, i, resultLevel1, writer, memRow);
#region Level 2
var loopLevel2 = (from row in LoopOrder.AsEnumerable()
where row.Field<int>(HIERARCHY_LEVEL) == 2
&& row.Field<string>(PARENT_LOOP).Trim() == loopIDofLoopOrder.Trim()
select row);
foreach (DataRow level2 in loopLevel2)
{
//Level 2
// ChildLoop = Convert.ToString(level2["PARENT_LOOP"]);// 1000C
ChildLoop = Convert.ToString(level2[LOOP_ID]);// 1100C
LoopID = ChildLoop;
var resultLevel2 = (from row in ValidationElementAttribute.AsEnumerable()
where row.Field<string>(LoopIdSegment).Trim() == ChildLoop.Trim()
select row);
//var healthCoverageIdList = memberEnrollment.Select(x => x.Field<object>(Health_Coverage_ID)).Distinct().ToList();
if (resultLevel2.Any())
{
int maxCount2;
if (String.IsNullOrEmpty(Convert.ToString(level2[Repeat_max])))
maxCount2 = maximumCount;
else
maxCount2 = Convert.ToInt32(level2[Repeat_max]);
//Custom Code
// maxCount2= ChildLoop == _2300 ? healthCoverageIdList.Count : maxCount2;
for (int j = 0; j < maxCount2; j++)
{
SkipLine = false;
//Custom Code
//if (ChildLoop == "2300")
//{
// WriteWholeLine(line, j, resultLevel2, writer, memRow, memberEnrollment.Where(x => x.Field<object>(Health_Coverage_ID) == healthCoverageIdList[j]).Select(x => x));
//}
//else
//{
//WriteWholeLine(line, j, resultLevel2, writer, memRow, memberEnrollment);
//}
WriteWholeLine(line, j, resultLevel2, writer, memRow);
if (HealthCoverageTbl.Any() && HealthCoverageTbl.Count() > j)
{
HealthCoverageID = Convert.ToString(HealthCoverageTbl.ElementAt(j).Field<string>(Health_Coverage_ID)).Trim();
}
else
{
HealthCoverageID = string.Empty;
}
#region Level 3
var loopLevel3 = (from row in LoopOrder.AsEnumerable()
where row.Field<int>(HIERARCHY_LEVEL) == 3
&& row.Field<string>(PARENT_LOOP).Trim() == ChildLoop.Trim()
select row);
foreach (DataRow level3 in loopLevel3)
{
//Level 3
ChildLoopLevel3 = Convert.ToString(level3[LOOP_ID]);
LoopID = ChildLoopLevel3;
var resultLevel3 = (from row in ValidationElementAttribute.AsEnumerable()
where row.Field<string>(LoopIdSegment).Trim() == ChildLoopLevel3.Trim()
select row);
if (resultLevel3.Any())
{
CobInfoTbl = CobInfoTblMaster.AsEnumerable().Where(x => x.Field<string>(Health_Coverage_ID).Trim() == HealthCoverageID).Select(x => x);
ProviderTbl = ProviderTblMaster.AsEnumerable().Where(x => x.Field<string>(Health_Coverage_ID).Trim() == HealthCoverageID).Select(x => x);
LXcounter = 0;
int maxCount3;
if (String.IsNullOrEmpty(Convert.ToString(level3[Repeat_max])))
maxCount3 = maximumCount;
else
maxCount3 = Convert.ToInt32(level3[Repeat_max]);
for (int k = 0; k < maxCount3; k++)
{
SkipLine = false;
if (CobInfoTbl.Any() && CobInfoTbl.Count() > k)
{
CobInfoID = CobInfoTbl.ElementAt(k).Field<string>(COB_ID);
}
else
{
CobInfoID = Convert.ToString("0");
}
//Not used : uncomment if Provider ID needed.
if (ProviderTbl.Any() && ProviderTbl.Count() > k)
{
ProviderID = ProviderTbl.ElementAt(k).Field<string>(Provider_ID).Trim();
}
else
{
ProviderID = string.Empty;
}
WriteWholeLine(line, k, resultLevel3, writer, memRow);
#region Level 4
var loopLevel4 = (from row in LoopOrder.AsEnumerable()
where row.Field<int>(HIERARCHY_LEVEL) == 4
&& row.Field<string>(PARENT_LOOP).Trim() == ChildLoopLevel3.Trim()
select row);
foreach (DataRow level4 in loopLevel4)
{
//Level 4
ChildLoopLevel4 = Convert.ToString(level4[LOOP_ID]);
LoopID = ChildLoopLevel4;
var resultLevel4 = (from row in ValidationElementAttribute.AsEnumerable()
where row.Field<string>(LoopIdSegment).Trim() == ChildLoopLevel4.Trim()
select row);
if (resultLevel4.Any())
{
int maxCount4;
if (String.IsNullOrEmpty(Convert.ToString(level4[Repeat_max])))
maxCount4 = maximumCount;
else
maxCount4 = Convert.ToInt32(level4[Repeat_max]);
for (int l = 0; l < maxCount4; l++)
{
SkipLine = false;
WriteWholeLine(line, l, resultLevel4, writer, memRow);
}
}
}
#endregion
}
}
}
#endregion
}
}
}
#endregion
}
}
}
// TODO : remove below break
// break;
}
//end of Regeneration
#endregion
return line;
}
if the order of the entries does not matter as in the results of each nested loop dont need to have the structure the foreach source has.
A->B->C->D->E each of those represent a nested loop, you could do it in parallel.
since all data manipulation should be the same, rewrite all foreach as in parallel. save the results to a collection like a ConcurrentDictionary

Incrementing an IEnumerator/IEnumerable while using yield

I am trying to yield iterate through a collection and if the collection is empty then call an increment method that will get the next set of results. When the increment says there are no more results then the yield with break;
I can not use (i think) a standard IEnumerator with MoveNext() etc as the increment method returns two different types of data.
I have tried an example below but it stops after one itteration. I am hoping there is a much easier way to do this (or at least is possible just I have a bug).
static void Main(string[] args)
{
var query = new Query();
foreach(var s in query.Q1())
{
Console.WriteLine(s);
}
foreach (var s in query.Q2())
{
Console.WriteLine(s);
}
Console.ReadLine();
}
public class Query
{
int i = 0;
bool complete;
List<string> q1 = new List<string>();
List<string> q2 = new List<string>();
public IEnumerable<string> Q1()
{
if (complete)
{
yield break;
}
if (!q1.Any() && !complete)
{
Increment();
}
if (q1.Any())
{
foreach (var s in q1)
{
yield return s;
}
}
}
public IEnumerable<string> Q2()
{
if (complete)
{
yield break;
}
if (!q2.Any() && !complete)
{
Increment();
}
if (q2.Any())
{
foreach (var s in q2)
{
yield return s;
}
}
}
void Increment()
{
if (i < 10)
{
// simulate getting two types of data back (parent and two children) from datasource
q1.Add((1 * (i + 1)).ToString());
q2.Add("A: " + (1 * (i + 1)).ToString());
q2.Add("B: " + (1 * (i + 1)).ToString());
i++;
}
else
{
complete = true;
}
}
}
result:
1
A: 1
B: 1
Any ideas on a better way of doing this or where I am going wrong?
EDIT
Here is my rough and ready fix:
public IEnumerable<string> Q1()
{
var index = 0;
if (!complete)
{
while (!complete)
{
var count = q1.Count();
if (index + 1 == count)
{
for (var x = index; index < count; index++)
{
yield return q1[index];
}
}
else
{
Increment();
}
}
}
else
{
foreach (var s in q1)
{
yield return s;
}
}
}
You are adding elements only to q2 list. Thus when you call Q1 iterator, you are exiting it after checking
if (q1.Any())
When you calling Q2 iterator, you exit it after
if (q2.Any())
{
foreach (var s in q2)
{
yield return s;
}
}
This foreach loop is executed only once and it returns only three items which where added to q2 during single Increment call in Q1 iterator.
It's not very clear what you want to achieve, but here is the way you can use loop for generating return values of iterator
public IEnumerable<string> Q2()
{
for (int i = 1; i <= 10; i++) // start from 1
{
yield return i.ToString(); // do not multiply by 1
yield return "A: " + i; // .ToString() is not necessary
yield return "B: " + i;
}
}

N-way intersection of sorted enumerables

Given n enumerables of the same type that return distinct elements in ascending order, for example:
IEnumerable<char> s1 = "adhjlstxyz";
IEnumerable<char> s2 = "bdeijmnpsz";
IEnumerable<char> s3 = "dejlnopsvw";
I want to efficiently find all values that are elements of all enumerables:
IEnumerable<char> sx = Intersect(new[] { s1, s2, s3 });
Debug.Assert(sx.SequenceEqual("djs"));
"Efficiently" here means that
the input enumerables should each be enumerated only once,
the elements of the input enumerables should be retrieved only when needed, and
the algorithm should not recursively enumerate its own output.
I need some hints how to approach a solution.
Here is my (naive) attempt so far:
static IEnumerable<T> Intersect<T>(IEnumerable<T>[] enums)
{
return enums[0].Intersect(
enums.Length == 2 ? enums[1] : Intersect(enums.Skip(1).ToArray()));
}
Enumerable.Intersect collects the first enumerable into a HashSet, then enumerates the second enumerable and yields all matching elements.
Intersect then recursively intersects the result with the next enumerable.
This obviously isn't very efficient (it doesn't meet the constraints). And it doesn't exploit the fact that the elements are sorted at all.
Here is my attempt to intersect two enumerables. Maybe it can be generalized for n enumerables?
static IEnumerable<T> Intersect<T>(IEnumerable<T> first, IEnumerable<T> second)
{
using (var left = first.GetEnumerator())
using (var right = second.GetEnumerator())
{
var leftHasNext = left.MoveNext();
var rightHasNext = right.MoveNext();
var comparer = Comparer<T>.Default;
while (leftHasNext && rightHasNext)
{
switch (Math.Sign(comparer.Compare(left.Current, right.Current)))
{
case -1:
leftHasNext = left.MoveNext();
break;
case 0:
yield return left.Current;
leftHasNext = left.MoveNext();
rightHasNext = right.MoveNext();
break;
case 1:
rightHasNext = right.MoveNext();
break;
}
}
}
}
OK; more complex answer:
public static IEnumerable<T> Intersect<T>(params IEnumerable<T>[] enums) {
return Intersect<T>(null, enums);
}
public static IEnumerable<T> Intersect<T>(IComparer<T> comparer, params IEnumerable<T>[] enums) {
if(enums == null) throw new ArgumentNullException("enums");
if(enums.Length == 0) return Enumerable.Empty<T>();
if(enums.Length == 1) return enums[0];
if(comparer == null) comparer = Comparer<T>.Default;
return IntersectImpl(comparer, enums);
}
public static IEnumerable<T> IntersectImpl<T>(IComparer<T> comparer, IEnumerable<T>[] enums) {
IEnumerator<T>[] iters = new IEnumerator<T>[enums.Length];
try {
// create iterators and move as far as the first item
for (int i = 0; i < enums.Length; i++) {
if(!(iters[i] = enums[i].GetEnumerator()).MoveNext()) {
yield break; // no data for one of the iterators
}
}
bool first = true;
T lastValue = default(T);
do { // get the next item from the first sequence
T value = iters[0].Current;
if (!first && comparer.Compare(value, lastValue) == 0) continue; // dup in first source
bool allTrue = true;
for (int i = 1; i < iters.Length; i++) {
var iter = iters[i];
// if any sequence isn't there yet, progress it; if any sequence
// ends, we're all done
while (comparer.Compare(iter.Current, value) < 0) {
if (!iter.MoveNext()) goto alldone; // nasty, but
}
// if any sequence is now **past** value, then short-circuit
if (comparer.Compare(iter.Current, value) > 0) {
allTrue = false;
break;
}
}
// so all sequences have this value
if (allTrue) yield return value;
first = false;
lastValue = value;
} while (iters[0].MoveNext());
alldone:
;
} finally { // clean up all iterators
for (int i = 0; i < iters.Length; i++) {
if (iters[i] != null) {
try { iters[i].Dispose(); }
catch { }
}
}
}
}
You can use LINQ:
public static IEnumerable<T> Intersect<T>(IEnumerable<IEnumerable<T>> enums) {
using (var iter = enums.GetEnumerator()) {
IEnumerable<T> result;
if (iter.MoveNext()) {
result = iter.Current;
while (iter.MoveNext()) {
result = result.Intersect(iter.Current);
}
} else {
result = Enumerable.Empty<T>();
}
return result;
}
}
This would be simple, although it does build the hash-set multiple times; advancing all n at once (to take advantage of sorted) would be hard, but you could also build a single hash-set and remove missing things?

Categories

Resources