This question already has answers here:
Difference between a List's Add and Append method?
(2 answers)
Closed 4 months ago.
https://dotnetfiddle.net/QHd0Rr#
I'm trying to populate a simple IEnumerable but I'm getting an error:
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
at System.Collections.Generic.List`1.get_Item(Int32 index)
at Program.Main()
Command terminated by signal 6
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var key1 = new WidgetA{Id = 1, Key = 52};
var key2 = new WidgetA{Id = 1, Key = 102};
var key3 = new WidgetA{Id = 1, Key = 152};
IEnumerable<WidgetA> list = Enumerable.Empty<WidgetA>();
list.Append(key1);
list.Append(key2);
list.Append(key3);
Console.WriteLine(list.ToList()[0]);
}
}
public class WidgetA
{
public int Id { get; set; }
public int Key { get; set; }
public string ValueToGet { get; set; }
}
Enumerable.Append<> is a lazy Linq function. If this is how you want to use it, you need to store the intermediate result:
IEnumerable<WidgetA> list = Enumerable.Empty<WidgetA>();
list = list.Append(key1);
list = list.Append(key2);
list = list.Append(key3);
While I really like (and upvoted) Blindy's answer and I think that it may better fit your need, here is an alternative with yield return:
public static void Main()
{
IEnumerable<int> list = DoStuff();
list.Dump();
}
public static IEnumerable<int> DoStuff()
{
yield return 0;
yield return 1;
// enter code here or whatever
yield return 2;
yield return 3;
yield return 4;
}
Related
I am having a bit of a frustrating time finding a simple method to compare and prove that the contents of two lists are equal. I have looked at a number of solutions on stackoverflow but I have not been successful. Some of the solutions look like they will require a large amount of work to implement and do something that on the face of it to my mind should be simpler, but perhaps I am too simple to realize that this cannot be done simply :)
I have created a fiddle with some detail that can be viewed here: https://dotnetfiddle.net/cvQr5d
Alternatively please find the full example below, I am having trouble with the object comparison method (variable finalResult) as it's returning false and if the content were being compared I would expect the value to be true:
using System;
using System.Collections.Generic;
using System.Linq;
public class ResponseExample
{
public Guid Id { get; set; } = Guid.Parse("00000000-0000-0000-0000-000000000000");
public int Value { get; set; } = 0;
public string Initials { get; set; } = "J";
public string FirstName { get; set; } = "Joe";
public string Surname { get; set; } = "Blogs";
public string CellPhone { get; set; } = "0923232199";
public bool EmailVerified { get; set; } = false;
public bool CellPhoneVerified { get; set; } = true;
}
public class Program
{
public static void Main()
{
var responseOne = new ResponseExample();
var responseTwo = new ResponseExample();
var responseThree = new ResponseExample();
var responseFour = new ResponseExample();
List<ResponseExample> objectListOne = new List<ResponseExample>();
objectListOne.Add(responseOne);
objectListOne.Add(responseTwo);
List<ResponseExample> objectListTwo = new List<ResponseExample>();
objectListTwo.Add(responseThree);
objectListTwo.Add(responseFour);
bool result = objectListOne.Count == objectListTwo.Count();
Console.WriteLine($"Count: {result}");
bool finalResult = ScrambledEquals<ResponseExample>(objectListOne, objectListTwo);
Console.WriteLine($"Object compare: {finalResult}");
}
//https://stackoverflow.com/a/3670089/3324415
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2)
{
var cnt = new Dictionary<T,
int>();
foreach (T s in list1)
{
if (cnt.ContainsKey(s))
{
cnt[s]++;
}
else
{
cnt.Add(s, 1);
}
}
foreach (T s in list2)
{
if (cnt.ContainsKey(s))
{
cnt[s]--;
}
else
{
return false;
}
}
return cnt.Values.All(c => c == 0);
}
}
As people in comments have pointed out this will not work as comparing a complex type by default compares whether the reference is the same. Field by field comparison will not work without implementing equality methods (and then you would need to overload GetHashCode and so on). See https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=net-5.0
However, if you can use c# 9, which is what you have in the fiddle you can define the type as a record instead of class. Records have built in field by field comparison. See https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records#characteristics-of-records
So public class ResponseExample would become public record ResponseExample and your code works as you expect.
Use Enumerable.All<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) Method which Determines whether all elements of a sequence satisfy a condition.
Once you have initilized your two List
list1.All(x=>list2.Contains(x))
This works by ensuring that all elements in list2 are containted in list1 otherwise returns false
Your method as is will compare if the 2 lists contain the same objects. So it is returning false as there are 4 different objects. If you create your list like this, using the same objects, it will return true:
List<ResponseExample> objectListOne = new List<ResponseExample>();
objectListOne.Add(responseOne);
objectListOne.Add(responseTwo);
List<ResponseExample> objectListTwo = new List<ResponseExample>();
objectListTwo.Add(responseTwo);
objectListTwo.Add(responseOne);
To get a true value when the contents of the objects are the same you could serialize the objects into a json string like this:
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2)
{
JavaScriptSerializer json = new JavaScriptSerializer();
var cnt = new Dictionary<string,
int>();
foreach (T _s in list1)
{
string s = json.Serialize(_s);
if (cnt.ContainsKey(s))
{
cnt[s]++;
}
else
{
cnt.Add(s, 1);
}
}
foreach (T _s in list2)
{
string s = json.Serialize(_s);
if (cnt.ContainsKey(s))
{
cnt[s]--;
}
else
{
return false;
}
}
return cnt.Values.All(c => c == 0);
}
If the performance is not a big deal, you can use Newtonsoft.Json. We will be able to compare different types of objects as well as run a deep equals check.
First install the package:
Install-Package Newtonsoft.Json
Here is the code snip:
public static bool DeepEqualsUsingJson<T>(IList<T> l1, IList<T> l2)
{
if (ReferenceEquals(l1, l2))
return true;
if (ReferenceEquals(l2, null))
return false;
if (l1.Count != l2.Count)
return false;
var l1JObject = l1.Select(i => JObject.FromObject(i)).ToList();
var l2JObject = l2.Select(i => JObject.FromObject(i)).ToList();
foreach (var o1 in l1JObject)
{
var index = l2JObject.FindIndex(o2 => JToken.DeepEquals(o1, o2));
if (index == -1)
return false;
l2JObject.RemoveAt(index);
}
return l2JObject.Count == 0;
}
This question already has answers here:
How to perform .Max() on a property of all objects in a collection and return the object with maximum value [duplicate]
(9 answers)
Closed 2 years ago.
I have that list:
Custom custom1 = new Custom(1, OtherCustom);
Custom custom2 = new Custom(2, OtherCustom);
Custom custom3 = new Custom(3, OtherCustom);
List<Custom> list = new List<Custom>();
list.Add(custom1);
list.Add(custom2);
list.Add(custom3);
I am really noob. Can someone help me achieve such a thing? :V
Custom custom = MAX ( list )
custom ---> {3, OtherCustom}
I need to take max by first parameter and still return whole object.
Another option is using list.Max() only and implement IComparable<Custom>, so your class would be:
public class Custom : IComparable<Custom>
{
public int Id { get; set; }
public OtherCustom OtherCustom { get; set; }
public Custom(int id, OtherCustom otherCustom)
{
Id = id;
OtherCustom = otherCustom;
}
public int CompareTo([AllowNull] Custom other)
{
return Id.CompareTo(other.Id);
}
}
And your max would pretty simple
Custom custom1 = new Custom(1, new OtherCustom());
Custom custom2 = new Custom(2, new OtherCustom());
Custom custom3 = new Custom(3, new OtherCustom());
Custom custom4 = new Custom(1, new OtherCustom());
List<Custom> list = new List<Custom>();
list.Add(custom1);
list.Add(custom2);
list.Add(custom3);
list.Add(custom4);
var item = list.Max();
Not clear what OtherCustom is, so I define a string to replace it.
You can get the "Max item" via linq as followed.
class Program
{
static void Main(string[] args)
{
Custom custom1 = new Custom(1, "OtherCustom1");
Custom custom2 = new Custom(2, "OtherCustom2");
Custom custom3 = new Custom(3, "OtherCustom3");
List<Custom> list = new List<Custom>();
list.Add(custom1);
list.Add(custom2);
list.Add(custom3);
int max = list.Max(i => i.Num);
Custom item = list.First(x => x.Num == max);
}
}
class Custom
{
int num;
string otherCustom;
public int Num
{
get { return num; }
}
public Custom(int n, string other)
{
num = n;
otherCustom = other;
}
}
this will return the max first parameter and it is a property of the Custom Class
var maxFirstParameterOfList = list.OrderByDescending(x => x.FirstParameterPropertyName).First();
if you want checking
var maxFirstParameterOfList = list.OrderByDescending(x => x.FirstParameterPropertyName).FirstOrDefault();
if (maxFirstParameterOfList != null)
{
return maxFirstParameterOfList;
}
This question already has answers here:
Natural Sort Order in C#
(18 answers)
Closed 4 years ago.
I am attempting to sort a List of fuses by the Designator property of the fuse.
The Fuse Model:
public class Fuse
{
public string Designator { get; set; }
public string Rating { get; set; }
public string Type { get; set; }
}
Example Data
This is an example of what a list of fuses would look like.
What I have tried:
fuses = fuses.OrderBy(f => f.Designator).ToList();
The above code sort of works, but it puts the F10 before F2. Does anyone know of a way to sort a List by the designator appropriately? I have read about natural sorting algorithms but not quite sure how to apply them correctly.
Any help would be greatly appreciated.
Thank you,
If you only compare string F2 the order will greater than F10.
You can try to order by number by Regex.
use ^F(\d+) pattern to get the number then order by.
fuses = fuses.OrderBy(f => int.Parse(Regex.Match(f.Designator, #"^F(\d+)").Groups[1].Value)).ToList();
You could implement IComparable<T>
class Fuse : IComparable<Fuse>
{
public string Designator { get; set; }
public int CompareTo(Fuse other)
{
if (string.IsNullOrWhiteSpace(other?.Designator)) return -1;
if (string.IsNullOrWhiteSpace(this.Designator)) return 1;
if (this.Designator == other.Designator) return 0;
// get the first item in the range
var d1Str = this.Designator.Split(new[] {',', '-'})[0];
var d2Str = other.Designator.Split(new[] {',', '-'})[0];
// parse to int
var d1 = int.Parse(d1Str.Substring(1));
var d2 = int.Parse(d2Str.Substring(1));
return d1 > d2 ? 1 : -1;
}
}
Test code
var list = new List<Fuse>()
{
new Fuse{Designator = "F8,F9"},
new Fuse{Designator = "F1,F2,F3"},
new Fuse{Designator = "F10-F12"},
new Fuse{Designator = "F4-F7"},
};
foreach (var itm in list.OrderBy(_ => _))
{
Console.WriteLine(itm.Designator);
}
Console.ReadLine();
Output
F1,F2,F3
F4-F7
F8,F9
F10-F12
You can try to sort it by integer instead. Throw away first letter, parse as integer and sort by this integer.
f => Int32.Parse(f.Designator.Substring(1))
Of course you can always refactor it out of lambda into something else.
This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 5 years ago.
I've defined a function in a class like this.
In this class, a value is either looked up or calculated if not found among a list of already calculate values.
If calculated anew, the result is stored in a list so that I can look it up in subsequent calls.
The problem is that the compiler doesn't like the way I do it and tells me
An object reference is required for the non-static field, method or property App.GetGoodFontSize(string, Size).
I don't understand what the compiler suggests. Which object reference does it mean?
Thank you.
public class App : Application
{
private List<udt> _list = new List<udt>();
private class udt
{
public int iLen { get; set; }
public Size nSize { get; set; }
public double FontSize { get; set; }
}
public double GetGoodFontSize(string uText, Xamarin.Forms.Size uTextRect)
{
for (int i = 0; i < _list.Count; i++)
{
if ((_list[i].iLen == uText.Length) && (_list[i].nSize == uTextRect))
{
return _list[i].FontSize;
}
}
int iBest = 100;
for (int i = 100; i > 6; i--)
{
Size nSize = GetTextSize(uText, i);
if (nSize.Width <= uTextRect.Width)
{
if (nSize.Height <= uTextRect.Height)
{
iBest = i;
break;
}
}
}
udt n = new udt();
n.iLen = uText.Length;
n.nSize = uTextRect;
n.FontSize = iBest;
_list.Add(n);
return iBest;
}
Change your code like this:
public static double GetGoodFontSize(string uText, Xamarin.Forms.Size uTextRect)
private static List<udt> _list = new List<udt>();
there is an error in this program.can anyone fix that?
Error is :TempRecord already defines a member called 'this' with the same parameters value
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
private int[] d= new int[10]{4,5,5,4,4,43,2,2,5,3};
// To enable client code to validate input
// when accessing your indexer.
//public int Length
//{
// get { return temps.Length; }
//}
// Indexer declaration.
// If index is out of range, the temps array will throw the exception.
public float this[int index]
{
get
{
return temps[index];
}
set
{
temps[index] = value;
}
}
public int this[int index]//error:TempRecord already defines a member called 'this' with the same parameters value
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
// Use the indexer's set accessor
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
// Use the indexer's get accessor
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
You have two members named this, that take the same parameters. That's not allowed in C# (or other .Net languages, as far as I'm aware).
You'd think you'd be able to do this if both members return different types, as yours do. But that would present the compiler with ambiguity. Which member would be called if you had code like this?
object x = tempRecord[3];
Make one or both indexers a method.
What you're trying to do is have 2 indexers with the same parameters and different return types. This is not legal in C#. You'll need to move at least one of them into a function
public int GetD(int index) {
return d[index];
}
public void SetD(int index, int value) {
d[index] = value;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F, 61.3F, 65.9F, 62.1F, 59.2F, 57.5F }; private int[] d = new int[10] { 4, 5, 5, 4, 4, 43, 2, 2, 5, 3 };
public int Length //
{
get { return temps.Length; }
}
public float this[int index]
{
get { return temps[index]; }
set { temps[index] = value; }
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
If you are trying some concept similar to overloading of functions, I'd like to say it never works with just a change in return type. Similar is the case of data members, where you have tried to use this with the same arguments but different return types.
The best method would be however (even for readability sake) making separate functions for the exclusive events that are being performed above.
I deleted the second data member above, replace it with the something like the foll. I think you better use temprecord.d[index Value] to access & use the member d from main.
public int d[int index]
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}