I need to access the current and previous element in an IQueryable object. If I had an int array, I would do the following:
var array = new int[]{0,1,2,3,4};
for(var i = 1; i<array.Length ; i++)
{
method1(array[i-1], array[i]);
}
I don't know to do the same with IQueryable, since it does not implement IList.
Using extension methods makes this fairly easy.
public static class IEnumerableExtensions
{
public static IEnumerable<ValueWithPrevious<T>> WithPrevious<T>(this IEnumerable<T> #this)
{
using (var e = #this.GetEnumerator())
{
if (!e.MoveNext())
yield break;
var previous = e.Current;
while (e.MoveNext())
{
yield return new ValueWithPrevious<T>(e.Current, previous);
previous = e.Current;
}
}
}
}
public struct ValueWithPrevious<T>
{
public readonly T Value, Previous;
public ValueWithPrevious(T value, T previous)
{
Value = value;
Previous = previous;
}
}
Usage:
var array = new int[] { 1, 2, 3, 4, 5 };
foreach (var value in array.WithPrevious())
{
Console.WriteLine("{0}, {1}", value.Previous, value.Value);
// Results: 1, 2
// 2, 3
// 3, 4
// 4, 5
}
You can turn an IQueryable<> into a List<> using ToList<>().
EDIT
Misread the question a bit. This code will give you consequetive elements
public static IEnumerable<Pair<T,T>> GroupIntoConsequetive(this IEnumerable<T> enumerable) {
using ( var e = enumerable.GetEnumerator() ) {
if ( !e.MoveNext() ) {
yield break;
}
var last = e.Current;
while ( e.MoveNext() ) {
yield return new Pair<T,T>(last, e.Current);
last = e.Current;
}
}
}
I'm not sure there is default way but writing an extension method to do so shouldn't be to difficult. I'm assuming there is a simple Pair implementation
public static IEnumerable<Pair<T,T>> Window(this IEnumerable<T> enumerable) {
using ( var e = enumerable.GetEnumerator() ) {
while ( e.MoveNext() ) {
var first = e.Current;
if ( !e.MoveNext() ) {
throw new InvalidOperationException("Need even number");
}
var second = e.Current;
yield return new Pair<T,T>(first,second);
}
}
}
With the window you could then get the behavior you desire with the following
var col = GetQueryableItem();
col.Window().Select(pair => method1(pair.First, pair.Second));
Quick and dirty Pair implementation
public struct Pair<T1,T2> {
public readonly T1 First;
public readonly T2 Second;
public Pair(T1 first, T2 second) {
First = first;
Second = second;
}
}
But it provides extension methods to create an array or a list from your IQueryable<T> instance, see ToArray() and ToList(). You can then go and do the same as you would with the array in your example.
IQueryable is IEnumerable. So you can do something like:
var a = new [] {1, 2, 3, 4}.AsQueryable();
if (a.Count() < 2) {
return;
}
var prev = a.First();
var isFirst = true;
foreach (var i in a) {
if (isFirst) {
isFirst = false;
continue;
}
method1(prev, i);
prev = i;
}
Or simply convert IQueryable into IList:
var list = a.ToList();
Related
I have two list object A and B like this:
A=[
{item:1, value:"ex1"},
{item:2, value:"ex1"},
{item:3, value:"ex1"},
{item:4, value:"ex1"}]
B=[{item:1, value:"ex2"},
{item:4, value:"ex2"},
{item:2, value:"ex3"},
{item:5, value:"ex3"}]
How can i do to make B to have same items/values like A and still keep its own sequence for items it already has?
I want B to remove item 5 because A don't have it, and add in item 3 to the end.
I don't want to clone A, I want to modify B to become like A.
What I want is:
Remove items in B when A don't have them: item5
Update items in B when both A and B have them: item1, item2, item4
Add non-existing items to end of B when A have them: item3
So, the result should be like this:
B = [ {item:1, value:"ex1"},
{item:4, value:"ex1"},
{item:2, value:"ex1"},
{item:3, value:"ex1"} ]
Mycode: (This is what i have now)
foreach (myClass itm in A)
{
foreach (myClass fd in B)
{
if (itm.item == fd.item)
{
fd.value = itm.value;
}
}
}
You can write an extension method that merges the lists by iterating over the keys and checking for existence.
static class ExtensionMethods
{
static public void MergeInto<TKey,TValue>(this Dictionary<TKey,TValue> rhs, Dictionary<TKey,TValue> lhs)
{
foreach (var key in rhs.Keys.Union(lhs.Keys).Distinct().ToList())
{
if (!rhs.ContainsKey(key))
{
lhs.Remove(key);
continue;
}
if (!lhs.ContainsKey(key))
{
lhs.Add(key, rhs[key]);
continue;
}
lhs[key] = rhs[key];
}
}
}
Test program:
public class Program
{
public static Dictionary<int,string> A = new Dictionary<int,string>
{
{ 1,"ex1" },
{ 2,"EX2" },
{ 3,"ex3" },
};
public static Dictionary<int,string> B = new Dictionary<int,string>
{
{ 1,"ex1" },
{ 2,"ex2" },
{ 4,"ex4" }
};
public static void Main()
{
A.MergeInto(B);
foreach (var entry in B )
{
Console.WriteLine("{0}={1}", entry.Key, entry.Value);
}
}
}
Output:
1=ex1
2=EX2
3=ex3
Code on DotNetFiddle
Without preserving order
If all you want to do is keep the instance of B, but make it so all its elements match A, you can just do this:
B.Clear();
B.AddRange(A);
Preserving order
If you want to preserve order, you can still use the solution above, but you will need to sort the list that is passed to AddRange(). This is only a little more work.
First, create a lookup table which tells you the order that that Item values originally appeared in. A generic c# Dictionary uses a hash table for the keys, so this is going to end up being more efficient than scanning the List repeatedly. Note that we pass B.Count to the constructor so that it only needs to allocate space once rather than repeatedly as it grows.
var orderBy = new Dictionary<int,int>(B.Count);
for (int i=0; i<B.Count; i++) orderBy.Add(B[i].Item, i);
Now we use our solution, sorting the input list:
B.Clear();
B.AddRange
(
A.OrderBy( item => orderBy.GetValueOrFallback(item.Item, int.MaxValue) )
);
GetValueOrFallback is a simple extension method on Dictionary<,> that makes it simpler to deal with keys that may or may not exist. You pass in the key you want, plus a value to return if the key is not found. In our case we pass int.MaxValue so that new items will be appended to the end.
static public TValue GetValueOrFallback<TKey,TValue>(this Dictionary<TKey,TValue> This, TKey keyToFind, TValue fallbackValue)
{
TValue result;
return This.TryGetValue(keyToFind, out result) ? result : fallbackValue;
}
Example
Put it all together with a test program:
public class MyClass
{
public int Item { get; set; }
public string Value { get; set; }
public override string ToString() { return Item.ToString() + "," + Value; }
}
static public class ExtensionMethods
{
static public TValue ValueOrFallback<TKey,TValue>(this Dictionary<TKey,TValue> This, TKey keyToFind, TValue fallbackValue)
{
TValue result;
return This.TryGetValue(keyToFind, out result) ? result : fallbackValue;
}
static public void MergeInto(this List<MyClass> mergeFrom, List<MyClass> mergeInto)
{
var orderBy = new Dictionary<int,int>(mergeFrom.Count);
for (int i=0; i<mergeInto.Count; i++) orderBy.Add(mergeInto[i].Item, i);
mergeInto.Clear();
mergeInto.AddRange
(
mergeFrom.OrderBy( item => orderBy.ValueOrFallback(item.Item, int.MaxValue) )
);
}
}
public class Program
{
public static List<MyClass> A = new List<MyClass>
{
new MyClass { Item = 2,Value = "EX2" },
new MyClass { Item = 3,Value = "ex3" },
new MyClass { Item = 1,Value = "ex1" }
};
public static List<MyClass> B = new List<MyClass>
{
new MyClass { Item = 1,Value = "ex1" },
new MyClass { Item = 2,Value = "ex2" },
new MyClass { Item = 4,Value = "ex3" },
};
public static void Main()
{
A.MergeInto(B);
foreach (var b in B) Console.WriteLine(b);
}
}
Output:
1,ex1
2,EX2
3,ex3
Code on DotNetFiddle
This is what you specify in the question. I tested it and it works:
class myClass
{
public int item;
public string value;
//ctor:
public myClass(int item, string value) { this.item = item; this.value = value; }
}
static void updateList()
{
var listA = new List<myClass> { new myClass(1, "A1"), new myClass(2, "A2"), new myClass(3, "A3"), new myClass(4, "A4") };
var listB = new List<myClass> { new myClass(1, "B1"), new myClass(4, "B4"), new myClass(2, "B2"), new myClass(5, "B5") };
for (int i = 0; i < listB.Count; i++) //use index to be able to use RemoveAt which is faster
{
var b = listB[i];
var j = listA.FindIndex(x => x.item == b.item);
if (j >= 0) //A has this item, update its value
{
var v = listA[j].value;
if (b.value != v) b.value = v;
}
else //A does not have this item
{
listB.RemoveAt(i);
}
}
foreach (var a in listA)
{
//if (!listB.Contains(a)) listB.Add(a);
if (!listB.Any(b => b.item == a.item)) listB.Add(a);
}
}
You can do something similar to this:
var listA = new List<int> { 1, 3, 5 };
var listB = new List<int> { 1, 4, 3 };
//Removes items in B that aren't in A.
//This will remove 4, leaving the sequence of B as 1,3
listB.RemoveAll(x => !listA.Contains(x));
//Gets items in A that aren't in B
//This will return the number 5
var items = listA.Where(y => !listB.Any(x => x == y));
//Add the items in A that aren't in B to the end of the list
//This adds 5 to the end of the list
foreach(var item in items)
{
listB.Add(item);
}
//List B should be 1,3,5
Console.WriteLine(listB);
I've got a Type that we'll call Foo that can hold a collection of children Foo objects. Foo is Disposable, so when ever a child is disposed of, it will then add itself to the parent's Children collection.
An example usage of this looks like:
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
In this example a1a is only added to a1 when it is disposed, and not before. What I am having difficulty in figuring out is a clean way of writing a GetAllFoos method that returns all of the objects in a flattened list, in a FILO order.
In this case, would I just recursively iterate over each child, or is there some fancy LINQ I can use to try and consolidate these collections? I'm using this to take performance measurement snapshots through-out the app, and it's possible that we would call GetAllMeasurements in some cases during a profile so the performance of the method call is important.
This is a complete example app that shows what the expected results would look like. I have to support both FIFO and FILO. I've got a FIFO implementation working but I'm not sure on the best way to handle this inversely for FILO.
using System;
using System.Collections.Generic;
using System.Linq;
namespace FILO_Example
{
public class Foo : IDisposable
{
internal Foo parent;
public Foo(Foo parent = null)
{
this.parent = parent;
}
public string Name { get; set; }
public List<Foo> Children { get; } = new List<Foo>();
public void Dispose() => this.parent.Children.Add(this);
}
class Program
{
public static Foo Root { get; } = new Foo { Name = "Root" };
static void Main(string[] args)
{
// level 1
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
using (var a2 = AddChild(a, "a2"))
{
}
}
using (var b = AddChild(Root, "b"))
{
using (var b1 = AddChild(b, "b1"))
{
}
}
List<Foo> allFoos = GetAllFoosFILO().ToList();
Console.WriteLine(allFoos[0]); // Should be b1
Console.WriteLine(allFoos[1]); // Should be b
Console.WriteLine(allFoos[2]); // Should be a2
Console.WriteLine(allFoos[3]); // Should be a1a
Console.WriteLine(allFoos[4]); // Should be a1
Console.WriteLine(allFoos[5]); // Should be a
}
static IEnumerable<Foo> GetAllFoosFILO()
{
return new List<Foo>();
}
static IEnumerable<Foo> GetAllFoosFIFO()
{
var fooStack = new Stack<Foo>();
fooStack.Push(Root);
while (fooStack.Count > 0)
{
Foo currentFoo = fooStack.Pop();
yield return currentFoo;
// If we have children, add them in reverse order so that it's a First-In-First-Out stack
// then the while loop will yield each child element.
if (currentFoo.Children.Count > 0)
{
List<Foo> fooChildren = currentFoo.Children;
for (int currentIndex = fooChildren.Count - 1; currentIndex >= 0; currentIndex--)
{
fooStack.Push(fooChildren[currentIndex]);
}
}
}
}
static Foo AddChild(Foo parent, string name)
{
var child = new Foo(parent) { Name = name };
return child;
}
}
}
As I mentioned in the comments, you have a tree structure. There is no fancy efficient standard LINQ solution, but you can utilize the quite efficient generic Traverse method form my answer to Enumerating Directories iteratively in "postorder":
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
With that helper, the GetAllFoosFIFO() is simple as that:
static IEnumerable<Foo> GetAllFoosFIFO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ? foo.Children : null);
}
while for GetAllFoosFILO() you need to pass preorder = false and iterate Children in reverse order:
static IEnumerable<Foo> GetAllFoosFILO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ?
Enumerable.Range(0, foo.Children.Count)
.Select(i => foo.Children[foo.Children.Count - 1 - i]) : null, false);
}
This should work:
private static IEnumerable<Foo> GetAllFoosFILO(Foo foo)
{
foreach (var c in ((IEnumerable<Foo>)foo.Children).Reverse())
{
var cc = GetAllFoosFILO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
yield return c;
}
}
The weird cast in first foreach loop is for preventing use of List<T>.Reverse instead of Enumerable.Reverse<TSource> extension method which helps us to traverse tree in so called FILO way.
Bonus
With some small touches you can write FIFO like:
private static IEnumerable<Foo> GetAllFoosFIFO(Foo foo)
{
foreach (var c in foo.Children)
{
yield return c;
var cc = GetAllFoosFIFO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
}
}
I would like to send to a method a list of numbers, and to get in return all the possible combinations of numbers I gen generate from this list by putting the digits next to each other.
For example, for the numbers {1, 2, 3} I would to give in return:
{1, 2, 3, 12, 13, 21, 23, 31, 32, 123, 132, 213, 231, 312, 321}
This code for example (which I haven't finished) only "Knows" to deal with lists that contain 3 numbers in them.
private static void M1()
{
var intList = new List<int>() { 1, 2, 3 };
var resultList = AllPossibleCombinations(intList);
}
private static object AllPossibleCombinations(List<int> List)
{
var result = new List<int>();
result.Add(List[0]);
result.Add(List[1]);
result.Add(List[2]);
result.Add(List[0] * 10 + List[1]);
result.Add(List[1] * 10 + List[2]);
result.Add(List[0] * 10 + List[2]);
result.Add(List[1] * 10 + List[0]);
result.Add(List[2] * 10 + List[1]);
result.Add(List[2] * 10 + List[0]);
return result;
}
How can I write something more generic? How can I get a list with different number of elements and give in return all the possible combinations?
This isn't necessarily the most efficient, but here's how you could do this using non-recursive methods returning IEnumerable<T>. Something like this will probably require the least possible memory, since it doesn't require building all the permutations in memory. Instead, it just allows you to iterate over the permutations one by one.
private static void Main()
{
var input1 = new[] {"1", "2", "3"};
foreach (var output in EnumeratePermutations(input1))
Debug.WriteLine(String.Join(",", output));
}
private static IEnumerable<T[]> EnumeratePermutations<T>(T[] input)
{
return from partCount in Enumerable.Range(1, input.Length)
let inputs = Enumerable.Repeat(input, partCount).ToArray()
from indices in EnumerateCrossjoinIndices(inputs)
where indices.Distinct().Count() == indices.Length
select indices.Select(n => input[n]).ToArray();
}
private static IEnumerable<int[]> EnumerateCrossjoinIndices(params Array[] arrays)
{
var arrayCount = arrays.Length;
if (arrayCount == 0)
yield break;
if (arrays.Any(a => a.Length == 0))
yield break;
var indexer = new int[arrayCount];
yield return (int[]) indexer.Clone();
for (var dimension = arrayCount - 1; dimension >= 0; --dimension)
{
++indexer[dimension];
if (indexer[dimension] == arrays[dimension].Length)
indexer[dimension] = 0;
else
{
yield return (int[]) indexer.Clone();
dimension = arrayCount;
}
}
}
EnumerateCrossjoinIndices takes n arrays of potentially different lengths and yields an enumeration of the indices that would be used in a crossjoin operation. For example, given {"1","2"} and {"A","B","C"}, it would yield 6 arrays {0,0}, {0,1}, {0,2}, {1,0}, {1,1}, {1,2}. Note that the arrays yielded by this method contain indices into the input arrays, not the elements at those indices.
EnumeratePermutations takes an array and yields the permutations of the items of that array. It does this by enumerating over the indices that would be used to crossjoin the array against itself x times (where x = 1 to n, where n is the number of items in the array). It then filters out any set of crossjoin indices where the set isn't a distinct set.
Try this sample code:
private static List<int> AllPossibleCombinations(IList<int> alphabet)
{
List<int[]> combinations = new List<int[]>();
MakeCombination(combinations, alphabet.Count, new int[0]); // Start recursion
combinations.RemoveAt(0); // Remove empty combination
return combinations.ConvertAll(c => c.Aggregate(0, (sum, index) => sum * 10 + alphabet[index]));
}
private static void MakeCombination(List<int[]> output, int length, int[] usedIndices)
{
output.Add(usedIndices);
for (int i = 0; i < length; i++)
if (Array.IndexOf(usedIndices, i) == -1) // If the index wasn't used earlier
{
// Add element to the array of indices by creating a new one:
int[] indices = new int[usedIndices.Length + 1];
usedIndices.CopyTo(indices, 0);
indices[usedIndices.Length] = i;
if (length + 1 != indices.Length)
MakeCombination(output, length, indices); // Recursion
}
}
It uses recursion to generate desired combinations.
Usage:
var t = AllPossibleCombinations(new[] { 1, 2, 3 });
Solution 1
The more generic and type independent way is to create tree-based algorithm which returns collection of combinations of input objects.
Code:
public static class IEnumerableExtensions
{
private class Node<T>
{
public Node()
{
Children = new List<Node<T>>();
}
public T Value
{
get;
set;
}
public bool IsRoot
{
get;
set;
}
public List<Node<T>> Children
{
get;
private set;
}
public Node<T> Parent
{
get;
set;
}
public List<Node<T>> Path
{
get
{
List<Node<T>> Result = new List<Node<T>>();
Result.Add(this);
if (this.Parent.IsRoot == false)
{
Result.AddRange(this.Parent.Path);
}
return Result;
}
}
}
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> enumerable)
{
List<Node<T>> AllNodes = new List<Node<T>>();
// Create tree.
Node<T> Root = new Node<T>() { IsRoot = true };
Queue<Node<T>> Queue = new Queue<Node<T>>();
Queue.Enqueue(Root);
int CurrentLevel = 0;
int LevelsToCreate = enumerable.Count();
while (Queue.Count > 0)
{
var CurrentLevelNodes = Queue.ToList();
Queue.Clear();
foreach (var LoopNode in CurrentLevelNodes)
{
if (LoopNode.Children.Count == 0)
{
foreach (var LoopValue in enumerable)
{
var NewNode = new Node<T>() { Value = LoopValue, Parent = LoopNode };
AllNodes.Add(NewNode);
LoopNode.Children.Add(NewNode);
Queue.Enqueue(NewNode);
}
}
}
CurrentLevel++;
if (CurrentLevel >= LevelsToCreate)
{
break;
}
}
// Return list of all paths (which are combinations).
List<List<T>> Result = new List<List<T>>();
foreach (var LoopNode in AllNodes)
{
if (!LoopNode.IsRoot)
{
List<T> Combination = LoopNode.Path.Select(Item => Item.Value).ToList();
Result.Add(Combination);
}
}
return Result;
}
}
Example with numbers:
class Program
{
static void Main(string[] args)
{
List<int> Input = new List<int>() { 1, 2, 3 };
var Combinations = Input.Combinations();
}
}
Example with strings:
static void Main(string[] args)
{
var Input = new List<string>() { "a", "b" };
var Combinations = Input.Combinations();
foreach (var LoopCombination in Combinations)
{
string Combination = string.Join(String.Empty, LoopCombination);
Console.WriteLine(Combination);
}
Console.ReadKey();
}
Solution 2
The second idea is to not to use tree-based algorithm and create combinations step-by-step - it may be faster.
Code:
public class Combinator<T>
{
private readonly Dictionary<int, T> _Pattern;
private readonly int _Min = 0;
private readonly int _Max;
private List<int> _CurrentCombination;
public Combinator(IEnumerable<T> pattern)
{
_Pattern = new Dictionary<int, T>();
for (int i = 0; i < pattern.Count(); i++)
{
_Pattern.Add(i, pattern.ElementAt(i));
}
_CurrentCombination = new List<int>();
_Max = pattern.Count() - 1;
}
public bool HasFinised
{
get;
private set;
}
public IEnumerable<T> Next()
{
// Initialize or increase.
if (_CurrentCombination.Count == 0)
{
_CurrentCombination.Add(_Min);
}
else
{
MyIncrease(_CurrentCombination.Count - 1);
}
if (_CurrentCombination.Count - 1 == _Max && _CurrentCombination.All(Key => Key == _Max))
{
HasFinised = true;
}
return _CurrentCombination.Select(Key => _Pattern[Key]).ToList();;
}
private void MyIncrease(int index)
{
if (index >= 0)
{
_CurrentCombination[index] = _CurrentCombination[index] + 1;
if (_CurrentCombination[index] > _Max)
{
_CurrentCombination[index] = _Min;
if (index - 1 < 0)
{
_CurrentCombination.Insert(0, -1);
index++;
}
MyIncrease(index - 1);
}
}
}
}
Example:
class Program
{
static void Main(string[] args)
{
var Pattern = new List<string>() { "a", "b", "c" };
Combinator<string> Combinator = new Combinator<string>(Pattern);
while (Combinator.HasFinised == false)
{
var Combined = Combinator.Next();
var Joined = string.Join("-", Combined);
Console.WriteLine(Joined);
}
Console.ReadKey();
}
}
If you want to combine items with others only:
static void Main(string[] args)
{
Combinator<int> Combinator = new Combinator<int>(new List<int>() { 1, 2, 3 });
while (Combinator.HasFinised == false)
{
var NextCombination = Combinator.Next();
var DistinctCheck = NextCombination.ToList().Distinct();
if (DistinctCheck.Count() == NextCombination.Count())
{
Console.WriteLine(string.Join(String.Empty, NextCombination.Select(Item => Item.ToString())));
}
}
Console.ReadKey();
}
I've a list like this:
var query = Enumerable.Range(0, 999).Select((n, index) =>
{
if (index <= 333 || index >=777)
return 0;
else if (index <= 666)
return 1;
else
return 2;
});
So, Can I find how much indexes have same value continuously? For example;
query[0]=query[1]=query[2]=query[3]... = 0, query[334] = 1, query[777]=query[778]... = 0.
First 334 indexes have 0, so first answer is 333. Also Last 223 indexes have 0, so second answer is 223..
How can I find these and their indexes?
Thanks in advance.
You can create extension for consecutive grouping of items by some key:
public static IEnumerable<IGrouping<TKey, T>> GroupConsecutive<T, TKey>(
this IEnumerable<T> source, Func<T, TKey> keySelector)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
yield break;
else
{
List<T> list = new List<T>();
var comparer = Comparer<TKey>.Default;
list.Add(iterator.Current);
TKey groupKey = keySelector(iterator.Current);
while (iterator.MoveNext())
{
var key = keySelector(iterator.Current);
if (!list.Any() || comparer.Compare(groupKey, key) == 0)
{
list.Add(iterator.Current);
continue;
}
yield return new Group<TKey, T>(groupKey, list);
list = new List<T> { iterator.Current };
groupKey = key;
}
if (list.Any())
yield return new Group<TKey, T>(groupKey, list);
}
}
}
Of course you can return IEnumerable<IList<T>> but that will be a little different from concept of group, which you want to have, because you also want to know which value was used to group sequence of items. Unfortunately there is no public implementation of IGrouping<TKey, TElement> interface, and we should create our own:
public class Group<TKey, TElement> : IGrouping<TKey, TElement>
{
private TKey _key;
private IEnumerable<TElement> _group;
public Group(TKey key, IEnumerable<TElement> group)
{
_key = key;
_group = group;
}
public TKey Key
{
get { return _key; }
}
public IEnumerator<TElement> GetEnumerator()
{
return _group.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now usage is very simple:
var groups = query.GroupConsecutive(i => i) // produces groups
.Select(g => new { g.Key, Count = g.Count() }); // projection
Result:
[
{ Key: 0, Count: 334 },
{ Key: 1, Count: 333 },
{ Key: 2, Count: 110 },
{ Key: 0, Count: 222 }
]
Using the GroupConsecutive extension method from here you can just get the counts of each group:
query.GroupConsecutive((n1, n2) => n1 == n2)
.Select(g => new {Number = g.Key, Count = g.Count()})
public static IEnumerable<int> GetContiguousCounts<T>(this IEnumerable<T> l, IEqualityComparer<T> cmp)
{
var last = default(T);
var count = 0;
foreach (var e in l)
{
if (count > 0 && !cmp.Equals(e, last))
{
yield return count;
count = 0;
}
count++;
last = e;
}
if (count > 0)
yield return count;
}
public static IEnumerable<int> GetContiguousCounts<T>(this IEnumerable<T> l)
{
return GetContiguousCounts(l, EqualityComparer<T>.Default);
}
static void Main(string[] args)
{
var a = new[] { 1, 2, 2, 3, 3, 3 };
var b = a.GetContiguousCounts();
foreach (var x in b)
Console.WriteLine(x);
}
For the simple test case, it outputs 1, 2, 3. For your case 334, 333, 110, 222 (the last value is not 223 as you asked in your question, because you only have 999 elements, not 1000).
erm, how about this, most efficient implementation I can think of.
IEnuemrable<KeyValuePair<T, int>> RepeatCounter<T>(
IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
var e = source.GetEnumerator();
if (!e.MoveNext())
{
yield break;
}
comparer = comparer ?? EqualityComparer<T>.Default;
var last = e.Current;
var count = 1;
while (e.MoveNext())
{
if (comparer.Equals(last, e.Current))
{
count++;
continue;
}
yield return new KeyValuePair<T, int>(last, count);
last = e.Current;
count = 1;
}
yield return new KeyValuePair<T, int>(last, count);
}
enumerates the sequence exactly once and only allocates variables when necessary.
I have a sorted list that will pass in two elements and compare the two. Is there a function in the SortedList class in C# that will do a next and previous? I got some help with a .Skip, but since the keys would be variable, how would that work? All I need to do is take in the first element and second element, then skip to the third and fourth, fifth and sixth, etc. I wish it were as simple as LinkedList's ".next.next."
double velocity = positionList.Values.Skip(1);
Edit: The positionList is type
<double, HandCoordinate>
HandCoordinate = {double, double, double}
Does that help?
Thanks!
The class SortedList inherites IEnumerator, so you can use it:
SortedList list = ...
var listEnumerator = ((IEnumerable)list).GetEnumerator();
Pair<MyType> pair = null
do
{
pair = Pair.Next<MyType>(listEnumerator);
...
}
while(pair != null)
...
class Pair<T>
{
public T First {get; set;}
public T Second {get; set;}
public static Pair<T> Next<T>(IEnumerator enumerator)
{
var first = enumerator.Current;
if(enumerator.MoveNext())
{
return new Pair<T>
{
First = (T)first,
Second = (T)enumerator.Current,
}
}
return null;
}
}
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
for (int i = 0; i < ints.Count; i += 2)
{
var pair = ints.Skip(i).Take(2);
var first = pair.First();
var last = pair.Last();
}
Note: This should work, irrelevant of the type in theory. Unless the type is a drastically different format.
Without Skip().
var pair = new { First = ints[i], Second = ints[i += 1] };
The question is somewhat unclear. I'm assuming you need to get pairs of things from a list?
It's fairly easy to write an extension method that will present a sequence of pairs of items from an IEnumerable:
using System;
using System.Collections.Generic;
namespace Demo
{
internal static class Program
{
public static void Main()
{
double[] test = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foreach (var pair in test.AsPairs()) // This is how you use it.
{
Console.WriteLine("({0}, {1})", pair.Item1, pair.Item2);
// Or simply: Console.WriteLine(pair);
}
}
}
public static class EnumerableExt
{
public static IEnumerable<Tuple<T, T>> AsPairs<T>(this IEnumerable<T> sequence)
{
bool isFirst = true;
T first = default(T);
foreach (var item in sequence)
{
if (isFirst)
{
first = item;
isFirst = false;
}
else
{
isFirst = true;
yield return new Tuple<T, T>(first, item);
}
}
}
}
}