Why Enumerator MoveNext() returns 0 - c#

Why next code generates loop hangs?
var x = new
{
Items = new List<int> { 1, 2, 3 }.GetEnumerator()
};
while (x.Items.MoveNext())
Console.WriteLine(x.Items.Current);
If I get enumerator after x initialization, than everything works fine:
var x = new
{
Items = new List<int> { 1, 2, 3 }
};
var enumerator = x.Items.GetEnumerator();
while (enumerator.MoveNext())
Console.WriteLine(enumerator.Current);
Tried to decompile both code blocks, but don't understand the reason:
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
var data1 = new \u003C\u003Ef__AnonymousType0<List<int>.Enumerator>(intList.GetEnumerator());
while (true)
{
List<int>.Enumerator items = data1.Items;
if (items.MoveNext())
{
items = data1.Items;
Console.WriteLine(items.Current);
}
else
break;
}
List<int> Items = new List<int>();
Items.Add(1);
Items.Add(2);
Items.Add(3);
var data2 = new \u003C\u003Ef__AnonymousType0<List<int>>(Items);
List<int>.Enumerator enumerator = data2.Items.GetEnumerator();
while (enumerator.MoveNext())
Console.WriteLine(enumerator.Current);

Because List's enumerator is a struct. In your first example, you're creating an enumerator object (somewhere, probably heap, doesn't matter) and every time you access it with .Items the enumerator gets copied onto the stack in your executing function. MoveNext mutates it and then the copied enumerator gets discarded. If it were a class, only the reference would be copied/discarded and the actual data modified but since it's a struct, you didn't modify the enumerator in var x { ... } at all. Enumerator.Current returns 0 because default(int) is zero but an exception would be possible, too.
In your second example you're creating a slot for the enumerator on the stack with var enumerator = x.Items.GetEnumerator(); and that slot gets accessed repeadedly without copies.

Related

Distinct Values in hashsets and insert in DataGridView

I want to display a hashset with all the different values ​​between two DataGridView, but I have not been successful in displaying the strings, I attach images.
var dataA = new HashSet<string>();
var dataB = new HashSet<string>();
for (int i = 1; i < dgv_A.Rows.Count; i++)
{
dataA.Add(dgv_A[8, i].Value.ToString());
}
for (int i = 1; i < dgv_B.Rows.Count; i++)
{
dataB.Add(dgv_B[8, i].Value.ToString());
}
if (dataA == dataB)
{
lbl_resultado.Text = "Las certificaciones estan correctas";
}
else
{
var error = dataA.Except(dataB).Concat(dataB.Except(dataA));
var container = new HashSet<string>(error);
dgv_B.DataSource = container.ToList();
}
Theres the values that are needed:
The result of the code:
NOTE: the if (dataA == dataB) part, it's not the problem i need answer but thanks. The part needed its:
else
{
var error = dataA.Except(dataB).Concat(dataB.Except(dataA));
var container = new HashSet<string>(error);
dgv_B.DataSource = container.ToList();
}
NOTE 2: The main operation of the project is the verification of documents (for example, that no user has been modified)
If any value is changed you need to know which values ​​were changed.
With
var error = dataA.Except(dataB).Concat(dataB.Except(dataA));
var container = new HashSet<string>(error);
dgv_B.DataSource = container.ToList();
I get the distinct values ​​fron dataA and dataB, but I can't get it to show me the texts that appear.
NOTE:
Here's your problem:
if (dataA == dataB)
{
}
The HashSet<T> type does not override the == operator.
Consequently dataA == dataB performs only a reference equality comparison, which means the same thing as Object.ReferenceEquals( dataA, dataB ), which will always be false, as dataA and dataB are references to separate GC objects.
Instead, to compare both HashSets to see if they are both equivalent use (the confusingly named) SetEquals() method:
if( dataA.SetEquals( dataB ) )
{
lbl_resultado.Text = "Las certificaciones estan correctas";
}
Do not use Enumerable.SequenceEquals because that evaluates the HashSet as an ordered sequence of values, but a HashSet is a Mathematical Set, which is unordered and (AFAIK) its HashSet<T>.Enumerator iterator returns its elements in undefined order, so attempting to check two sets' set-equality by comparing sequences is incorrect.

How to add index range of one string list to another string list

I am new to c# and recoding some python into c#. How would you take a range of one list (list1) and create a new shorter list of it(list2)?
python
list1= ["lets", "go", "visit", "houston", "texas"]
list2 = []
list2.append(list1[3:4]) ##new list is ["houston", "texas"]
#or
list2.append(list1[3:]) ##new list is ["houston", "texas"]
How would this look in c#?
private void button1_Click(object sender, EventArgs e)
{
List < string > list1 = new List < string > ();
list1.Add("lets");
list1.Add("go");
list1.Add("visit")
list1.Add("houston");
list1.Add("texas");
List<string> list2 = list1.GetRange(3, 4);
}
Is there a better way to get list index ranges? And how to begin the index, list1[:3] or index to end list1[3:]
This would be the C# equivalent:
var list1 = new List<string> { "lets", "go", "visit", "houston", "texas" };
var list2 = new List<string>();
list2.AddRange(list1.Skip(3).Take(2 /* there is 2 elements from 3rd to 4th*/));
// or
list2.AddRange(list1.Skip(3));
Edit: You can extend the list with custom methods:
public static class ListExtensions
{
public static List<T> Slice<T>(this List<T> list, int? start = null, int? end = null)
{
if (start.HasValue)
return list.GetRange(start.Value, (end.HasValue ? (end.Value + 1) : list.Count) - start.Value);
if (end.HasValue) // not sure [:n] returns last n elements?
return list.GetRange(list.Count - end.Value, end.Value);
return list;
}
}
var list1 = new List<string> { "lets", "go", "visit", "houston", "texas" };
list1.Slice(3) // houston, texas
list1.Slice(3, 4) // houston, texas
list1.Slice(null, 3) // visit, houston, texas
You can do this using the GetRange method of List<T>:
List<string> list2 = list1.GetRange(3, 2); // Take two items starting at index 3
List<string> list2 = list1.GetRange(0, 3); // Take from the beginning up to index 3
List<string> list2 = list1.GetRange(3, list1.Count - 3); // Take from index 3 to the end
Or, alternatively, by using the Linq extension methods Skip and Take (using System.Linq):
List<string> list2 = list1.Skip(3).Take(2).ToList(); // Take two items starting at index 3
List<string> list2 = list1.Take(3).ToList(); // Take from the beginning up to index 3
List<string> list2 = list1.Skip(3).ToList(); // Take from index 3 to the end
Firstly, note that GetRange is defined as:
System.Collections.Generic.List<T> GetRange (int index, int count);
Where index is the zero-based List<T> index at which the range
starts.
count is the number of elements in the range.
Thus, you doing list1.GetRange(3, 4); will yield a System.ArgumentException: as count i.e. 4 does not denote a valid range of elements in the list.
Further, using GetRange is as good as it gets if you want to copy a specific range of a list.
In order to yield a list containing "houston" and "texas" you can call GetRange with 3 as the index and 2 as the count of elements.
list1.GetRange(3, 2); // ["houston", "texas"]
Unfortunately, there's no GetRange taking only a "begin index".
Instead, if you don't want to specify the Count in GetRange then use Skip then collect to a list:
list1.Skip(3).ToList(); // ["houston", "texas"]
Alternatively, if you want to add to an "existing" list then use AddRange + GetRange:
list2.AddRange(list1.GetRange(3, 2)); // ["houston", "texas"]
You can use the Array.Copy() method. This will allow you to copy a specified range of elements in one Array to another Array.
See documentation here.

Double-use of C# iterator works unexpectedly

This is my first go at coding in C# - I have a background in C/Python/Javascript/Haskell.
Why does the program below work? I would expect this to work in Haskell, as lists are immutable, but I am struggling with how I can use the same iterator nums twice, without error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
var nums = new List<int?>() { 0, 0, 2, 3, 3, 3, 4 };
var lastNums = new List<int?>() { null } .Concat(nums);
var changesAndNulls = lastNums.Zip(nums,
(last, curr) => (last == null || last != curr) ? curr : null
);
var changes = from changeOrNull in changesAndNulls where changeOrNull != null select changeOrNull;
foreach (var change in changes) {
Console.WriteLine("change: " + change);
}
}
}
}
In your code nums is not IEnumerator<T> (iterator), it's IEnumarable<T> and IEnumarable <T> has GetEnumerator() method which can be invoked as many times as required:
IEnumerable<int?> nums = new List<int?>() { 0, 0, 2, 3, 3, 3, 4 };
// Linq gets enumerator to do Concat
using (var iterator1 = nums.GetEnumerator()) {
while (iterator1.MoveNext()) {
...
}
}
...
// Linq gets (fresh!) enumerator to do Zip
using (var iterator2 = nums.GetEnumerator()) {
while (iterator2.MoveNext()) {
...
}
}
So IEnumerable<T> is a factory producing IEnumerator<T> instances (and it is a IEnumerator<T> that can't be re-used)
A List<int?> implements the interface IEnumerable<int?>. That means it has a method called GetEnumerator().
This method returns a new Enumerator<int?> object used to iterate over all the items.
You are calling GetEnumerator() (in the background) when you use it inside a foreach loop or when you call one of the many extension methods like Concat() (which call GetEnumerator() themselves).
I suggest you take a tutorial on C#. It is a very different language than Haskell and it has some very unique features.
Just for starters: http://en.wikipedia.org/wiki/C_Sharp_syntax

Test if all values in a list are unique

I have a small list of bytes and I want to test that they're all different values.
For instance, I have this:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
What's the best way to check if all values are distinct or not?
bool isUnique = theList.Distinct().Count() == theList.Count();
Here's another approach which is more efficient than Enumerable.Distinct + Enumerable.Count (all the more if the sequence is not a collection type). It uses a HashSet<T> which eliminates duplicates, is very efficient in lookups and has a count-property:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
or another - more subtle and efficient - approach:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Add returns false if the element could not be added since it was already in the HashSet. Enumerable.All stops on the first "false".
Okay, here is the most efficient method I can think of using standard .Net
using System;
using System.Collections.Generic;
public static class Extension
{
public static bool HasDuplicate<T>(
this IEnumerable<T> source,
out T firstDuplicate)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var checkBuffer = new HashSet<T>();
foreach (var t in source)
{
if (checkBuffer.Add(t))
{
continue;
}
firstDuplicate = t;
return true;
}
firstDuplicate = default(T);
return false;
}
}
essentially, what is the point of enumerating the whole sequence twice if all you want to do is find the first duplicate.
I could optimise this more by special casing an empty and single element sequences but that would depreciate from readability/maintainability with minimal gain.
The similar logic to Distinct using GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
I check if an IEnumerable (aray, list, etc ) is unique like this :
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
One can also do: Use Hashset
var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));
if (uniqueIds.Count != originalList.Count)
{
}
There are many solutions.
And no doubt more beautiful ones with the usage of LINQ as "juergen d" and "Tim Schmelter" mentioned.
But, if you bare "Complexity" and speed, the best solution will be to implement it by yourself.
One of the solution will be, to create an array of N size (for byte it's 256).
And loop the array, and on every iteration will test the matching number index if the value is 1 if it does, that means i already increment the array index and therefore the array isn't distinct otherwise i will increment the array cell and continue checking.
And another solution, if you want to find duplicated values.
var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };
var sorted = values.ToList();
sorted.Sort();
for (var index = 1; index < sorted.Count; index++)
{
var previous = sorted[index - 1];
var current = sorted[index];
if (current == previous)
Console.WriteLine(string.Format("duplicated value: {0}", current));
}
Output:
duplicated value: 2
duplicated value: 7
http://rextester.com/SIDG48202

How to iterate through two collections of the same length using a single foreach

I know this question has been asked many times before but I tried out the answers and they don't seem to work.
I have two lists of the same length but not the same type, and I want to iterate through both of them at the same time as list1[i] is connected to list2[i].
Eg:
Assuming that i have list1 (as List<string>) and list2 (as List<int>)
I want to do something like
foreach( var listitem1, listitem2 in list1, list2)
{
// do stuff
}
Is this possible?
This is possible using .NET 4 LINQ Zip() operator or using open source MoreLINQ library which provides Zip() operator as well so you can use it in more earlier .NET versions
Example from MSDN:
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
// The following example concatenates corresponding elements of the
// two input sequences.
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
{
Console.WriteLine(item);
}
// OUTPUT:
// 1 one
// 2 two
// 3 three
Useful links:
Soure code of the MoreLINQ Zip() implementation: MoreLINQ Zip.cs
Edit - Iterating whilst positioning at the same index in both collections
If the requirement is to move through both collections in a 'synchronized' fashion, i.e. to use the 1st element of the first collection with the 1st element of the second collection, then 2nd with 2nd, and so on, without needing to perform any side effecting code, then see #sll's answer and use .Zip() to project out pairs of elements at the same index, until one of the collections runs out of elements.
More Generally
Instead of the foreach, you can access the IEnumerator from the IEnumerable of both collections using the GetEnumerator() method and then call MoveNext() on the collection when you need to move on to the next element in that collection. This technique is common when processing two or more ordered streams, without needing to materialize the streams.
var stream1Enumerator = stream1.GetEnumerator();
var stream2Enumerator = stream2.GetEnumerator();
var currentGroupId = -1; // Initial value
// i.e. Until stream1Enumerator runs out of
while (stream1Enumerator.MoveNext())
{
// Now you can iterate the collections independently
if (stream1Enumerator.Current.Id != currentGroupId)
{
stream2Enumerator.MoveNext();
currentGroupId = stream2Enumerator.Current.Id;
}
// Do something with stream1Enumerator.Current and stream2Enumerator.Current
}
As others have pointed out, if the collections are materialized and support indexing, such as an ICollection interface, you can also use the subscript [] operator, although this feels rather clumsy nowadays:
var smallestUpperBound = Math.Min(collection1.Count, collection2.Count);
for (var index = 0; index < smallestUpperBound; index++)
{
// Do something with collection1[index] and collection2[index]
}
Finally, there is also an overload of Linq's .Select() which provides the index ordinal of the element returned, which could also be useful.
e.g. the below will pair up all elements of collection1 alternatively with the first two elements of collection2:
var alternatePairs = collection1.Select(
(item1, index1) => new
{
Item1 = item1,
Item2 = collection2[index1 % 2]
});
Short answer is no you can't.
Longer answer is that is because foreach is syntactic sugar - it gets an iterator from the collection and calls Next on it. This is not possible with two collections at the same time.
If you just want to have a single loop, you can use a for loop and use the same index value for both collections.
for(int i = 0; i < collectionsLength; i++)
{
list1[i];
list2[i];
}
An alternative is to merge both collections into one using the LINQ Zip operator (new to .NET 4.0) and iterate over the result.
foreach(var tup in list1.Zip(list2, (i1, i2) => Tuple.Create(i1, i2)))
{
var listItem1 = tup.Item1;
var listItem2 = tup.Item2;
/* The "do stuff" from your question goes here */
}
It can though be such that much of your "do stuff" can go in the lambda that here creates a tuple, which would be even better.
If the collections are such that they can be iterated, then a for() loop is probably simpler still though.
Update: Now with the built-in support for ValueTuple in C#7.0 we can use:
foreach ((var listitem1, var listitem2) in list1.Zip(list2, (i1, i2) => (i1, i2)))
{
/* The "do stuff" from your question goes here */
}
You can wrap the two IEnumerable<> in helper class:
var nums = new []{1, 2, 3};
var strings = new []{"a", "b", "c"};
ForEach(nums, strings).Do((n, s) =>
{
Console.WriteLine(n + " " + s);
});
//-----------------------------
public static TwoForEach<A, B> ForEach<A, B>(IEnumerable<A> a, IEnumerable<B> b)
{
return new TwoForEach<A, B>(a, b);
}
public class TwoForEach<A, B>
{
private IEnumerator<A> a;
private IEnumerator<B> b;
public TwoForEach(IEnumerable<A> a, IEnumerable<B> b)
{
this.a = a.GetEnumerator();
this.b = b.GetEnumerator();
}
public void Do(Action<A, B> action)
{
while (a.MoveNext() && b.MoveNext())
{
action.Invoke(a.Current, b.Current);
}
}
}
Instead of a foreach, why not use a for()? for example...
int length = list1.length;
for(int i = 0; i < length; i++)
{
// do stuff with list1[i] and list2[i] here.
}

Categories