So I'm trying to append values to a list (in Json []), that's empty or has items in it. So I check wether the list in the object has items in it or not, if the item doesn't exist, then it creates a new item, if it exists, it rewrites it's value. Here is the code:
if (e.Key == Key.Enter)
{
// When the user pressed enter, do action
Team selected_team = teams.Where(t => t.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
if (selected_team != null)
{
// when the team number is given, go try and find the data of them
Results team_results = results.Where(r => r.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
int index = (Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1);
// Check if the item in the list exists
if (index < team_results.results[inp_tour_part.SelectedIndex].gtks.Length && team_results.results[inp_tour_part.SelectedIndex].gtks[index] != null)
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = gtk_input.Text; // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = "00:00"; // Give the default value
}
}
else
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks.Append(gtk_input.Text); // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks.Append("00:00"); // Give the default value
}
}
SaveResults(results);
// Move to the next UI element
MoveToNextUIElement(e);
}
else
{
MessageBox.Show("Something went somewhere wrong.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
Now, it works fine to rewrite the items, but when the list is empty (default) or when the item doesn't exist, and it needs to add/append the new value, it doesn't crahs and doesn't throw any error... Also it doesn't add the value to my json, now when I initialize the new object for this, it looks like the following:
team_results = new Results()
{
team_number = selected_team.team_number,
results = new Result[2] { new Result{ }, new Result { } } // Fixed length of array for the results. TODO: Needs fix.
};
And the model looks like this:
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public string[] gtks { get; set; }
}
}
Now I just need a list of strings in my json, but I don't have any clue on how to achieve this...
If you MUST, you can resize an array using Array.Resize() method. Please see documentation here.
int[] array = new int[] { 1, 2, 3 };
Array.Resize(ref array, 5);
array[3] = 4;
array[4] = 5;
But it is strongly advised the use of List<T> instead of arrays. After all List<T> uses arrays behind the scenes so you get all the functionality of an array minus most of the cons.
You can use List instead. Thus you don't need to know the array size when instantiating the list.
Why not alter your models so they implement List instead of array. In the constructor of each model just initialize the empty list (or other action depending on your situation)
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public List<Result> results { get; set; }
public Results() {
results = new List<Result>();
}
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public List<string> gtks { get; set; }
public Result() {
gtks = new List<string>();
}
}
}
Then when you have your models you can add to each list like the following:
Results r = new Results();
r.results.Add(new Result()); // or other `result` object here
Result r = new Result();
r.gtks.Add("My String"); // or other `string` here
I think you can implement a method which would create a new array based on original one. Then, you would be able to override that original array with the resulted one (returned by that new method).
The example code would be the following:
var test = new string[1] { "Test string 1" };
test = AddItemToArray(test, "Test string 2");
private static string[] AddItemToArray(string[] original, string item)
{
var result = new string[original.Length + 1];
for (int i = 0; i < original.Length; i++)
{
result[i] = original[i];
}
result[result.Length - 1] = item;
return result;
}
Related
I have this json string and i want to get the 4th line (iValue, sValue) of every record.
My problem here is the keys vary for every record (based on the data type of the value).
Is there any way to do this on C#?
Here is an example:
{ "data": [
{
"pKey": "0",
"Entity": "tableName",
"Attribute": "CID",
"iValue": "13"
},
{
"pKey": "0",
"Entity": "tableName",
"Attribute": "username",
"sValue": "test_user1"
}] }
Here is kind of a big implementation, you will have to implement this for each iValue, fValue, etc however, it speeds up the implementation and usage. First of, here is the usage:
string rawJson = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var values = JsonConvert.DeserializeObject<TakeData>(rawJson).Data.Select(v => v.PureData);
Now values contains the list. Here is the usage for accessing each:
foreach (var val in values)
{
if (val is IntData i)
{
int myInt = i.iValue;
// use the rest of the properties
}
else if (val is StrData s)
{
string myStr = s.sValue;
// use the rest of the properties
}
}
And here is the implementation:
class TakeData
{
public List<TakeItAll> Data { get; set; }
}
class TakeItAll
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
private int _iValue;
public int iValue
{
get => _iValue;
set
{
_iValue = value;
PureData = new IntData { pKey = pKey, Entity = Entity, Attribute = Attribute, iValue = iValue };
}
}
private string _sValue;
public string sValue
{
get => _sValue;
set
{
_sValue = value;
PureData = new StrData { pKey = pKey, Entity = Entity, Attribute = Attribute, sValue = sValue };
}
}
public IPureData PureData { get; private set; }
}
interface IPureData
{
int pKey { get; set; }
string Entity { get; set; }
string Attribute { get; set; }
}
class IntData : IPureData
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public int iValue { get; set; }
}
class StrData : IPureData
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public string sValue { get; set; }
}
Of course you can use some alternatives as well. Such as using an enum in TakeItAll to keep track of the data type (or a type variable) instead of so many classes. This way However the size of the values object would be larger.
class TakeItAll
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
private int _iValue;
public int iValue
{
get => _iValue;
set
{
_iValue = value;
ValType = typeof(string);
}
}
private string _sValue;
public string sValue
{
get => _sValue;
set
{
_sValue = value;
ValType = typeof(int);
}
}
public Type ValType { get; private set; }
}
I would deserialize this into an object supporting both types of properties and then by code try parsing either the integer or the string if the integer fails.
If the Attribute value gives you a clue as to which one to look for, you could also use that to prevent having to try parsing the integer every time.
I would not rely on the property being the "fourth" property every time, as I'm assuming this would be external data, where you may not be able to control whether these properties come out in the exact same order every time (now and in the future).
If you don't know the data type then you could use an object to handle it.
It's a good idea to deserialize JSON string to concrete class to avoid string manipulation mistake.
public class Datum
{
public object pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public string iValue { get; set; }
public string sValue { get; set; }
}
public class DataCollection
{
public List<Datum> data { get; set; }
}
public void Test()
{
var str = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var list = JsonConvert.DeserializeObject<DataCollection>(str);
var keys = list.data.Select(x => x.pKey).ToList();
}
Another option is to deserialize to dynamic and inspect that:
var json = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var result = JsonConvert.DeserializeAnonymousType<dynamic>(json, null);
if (result.data != null)
{
for (var i = 0; i < result.data.Count; i++)
{
if (result.data[i]["iValue"] != null)
// Parse iValue
if (result.data[i]["sValue"] != null)
// Parse sValue
}
}
You could load the Json in a ExpandoObject
var expConverter = new ExpandoObjectConverter();
dynamic objList = JsonConvert.DeserializeObject<List<ExpandoObject>>(json, expConverter);
JSON array to ExpandoObject via JSON.NET
Then once you have loaded it in as a List<ExpandoObject> you may itterate over it as a dictionary.
foreach(var obj in objList)
{
//convert the object to a Dictionary and select the 4th element.
var yourresult = (obj as IDictionary<string, object>).ElementAt(3);
}
My two cents:
Get each object of the array as a KeyValuePair
var json = "your json here";
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var element in root.Data)
{
//===================================================> Here using object because your value type change. You can change it to string if your value is always wrapped in a string (like "13")
var keyValuePair = element.ToObject<Dictionary<string, object>>();
//here, for each object of the 'data' array, you can check if the desidered property exists
if (keyValuePair.ContainsKey("iValue"))
{
var propertyValue = keyValuePair["iValue"];
}
else if (keyValuePair.ContainsKey("sValue"))
{
var propertyValue = keyValuePair["sValue"];
}
// Or you can check the property name in the desidered position
if (keyValuePair.Keys.ElementAt(3) == "iValue")
{
var propertyValue = keyValuePair["iValue"];
}
else if (keyValuePair.Keys.ElementAt(3) == "sValue")
{
var propertyValue = keyValuePair["sValue"];
}
}
Where Root is
class Root
{
[JsonProperty("data")]
public List<JObject> Data { get; set; }
}
With this solution you can always know which property (iValue or sValue) is specified. On the contrary, if you use a model class which has both property names, you wouldn't know which property is specified when the value is null (unless you use additional properties/classes and a custom JsonConverter).
Edit
As Panagiotis Kanavos reminded me, the JObject class implements IDictionary<string, JToken>. So, inside your foreach you could use:
if (element["iValue"] != null)
{
var propertyValue = element["iValue"].Value<string>();
}
if (element["sValue"] != null)
{
var propertyValue = element["sValue"].Value<string>();
}
// Or you can check the property name in the desidered position
var propName = element.Properties().ElementAt(3).Name;
if (propName == "iValue")
{
var propertyValue = keyValuePair["iValue"].Value<string>();
}
else if (propName == "sValue")
{
var propertyValue = keyValuePair["sValue"].Value<string>();
}
Of course you can optimize this code and check for nulls.
Im making a new years eve quiz for some friends. The quiz itself is done and working I just thought it would be cool to autocorrect the answers once they are posted.
The question is what's the best way to compare the posted object with an object that has all the right answers, reflection?. There has to be a slick way to do it and avoid having a lot of if's.
public class QuizModel
{
public string Name { get; set; }
public string Quiz1 { get; set; }
public string Quiz2 { get; set; }
public string Quiz3 { get; set; }
etc..
}
You dont have to write me any code. I just want some directions on what the best ( and most important the coolest) way to do it :)
As for your explanation, the implementation of this class should be a list of answers (or a dictionary, or an array, etc):
public class QuizModel
{
public string Name { get; set; }
public List<string> Quizs { get; set; }
}
Then, to check if all the answers are the same:
public bool AreEqual(model1, model2){
for(var i = 0; i < Math.Min(model1.Quizs.Count, model2.Quizs.Count); ++i)
if(model1.Quizs[i] != model2.Quizs[i])
return false;
return true;
}
In a similar way you can get the number of answers that are identical.
You don't need to use reflection to compare values, no :)
If all of the values are encapsulated within a model, then so should be the comparison logic. One simple approach could be to just override .Equals(). Something like this:
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is QuizModel))
return false;
var quiz = obj as QuizModel;
return
quiz.Name.Equals(this.Name) &&
quiz.Quiz1.Equals(this.Quiz1) &&
// etc.
}
Of course, that's the easy part. The real challenge is going to be that string comparison logic. Strings sounds like free text input. So if one of the answers is "Christmas Day" then what do you do with inputs like "Christmas day" or "christmas" or "december 25th" and so on? That's up to your business logic. But the actual logic of "are these two objects equal" is pretty straightforward.
Semantically you might choose not to override .Equals() for this purpose. I could see a good argument against it, claiming that the objects are different but simply contain the same values. (A great real world example of this are identical twins.) So you may choose to implement something else, like IEquatable or just a custom method like .IsEqualTo(QuizModel quiz). But the logic therein would be the same either way.
I'm giving you two solutions to your question. I think you want to give scores to your friends(I would do that). If so, here is a solution that give you the score for the answer, I'm supposing that every quiz has the same value and you have the correct answer for all the quiz. First you could try by reflection compare all the values of the quizes, and return total(assuming your quizes have the same value. Then if you want to be more flexible below I suggest you a possible solution when the quizes may have a different value(score).
1)
public class QuizModel
{
public string Name { get; set; }
public string Quiz1 { get; set; }
public string Quiz2 { get; set; }
public string Quiz3 { get; set; }
}
public class QuizComparer
{
public QuizComparer(QuizModel correctOne, IComparer<string> comparer, int quizValue = 1)
{
this.CorrectOne = correctOne;
this.Comparer = comparer;
this.QuizValue = quizValue;
}
public int Compare(QuizModel toCompareOne)
{
Type type = toCompareOne.GetType();
var propertiesInfo = type.GetProperties();
int result = 0;
foreach (var propertyInfo in propertiesInfo)
{
if (propertyInfo.CanRead)
{
var toCompareOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(toCompareOne).ToString();
var correctOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(this.CorrectOne).ToString();
if (Comparer.Compare(toCompareOnePropertyValue, correctOnePropertyValue) == 0)//equals
{
result += QuizValue;
}
}
}
return result;
}
public QuizModel CorrectOne { get; set; }
public IComparer<string> Comparer { get; set; }
public int QuizValue { get; set; }
}
2) Secondly if you want to give to your quizes individual scores, you could find this very helpful:
public class QuizModel
{
public string Name { get; set; }
[QuizValue(value: 1)]
public string Quiz1 { get; set; }
[QuizValue(value: 2)]
public string Quiz2 { get; set; }
[QuizValue(value: 3)]
public string Quiz3 { get; set; }
}
public class QuizComparer
{
public QuizComparer(QuizModel correctOne, IComparer<string> comparer, int quizValue = 1)
{
this.CorrectOne = correctOne;
this.Comparer = comparer;
this.QuizDefaultValue = quizValue;
}
public int Compare(QuizModel toCompareOne)
{
Type type = toCompareOne.GetType();
var propertiesInfo = type.GetProperties();
int result = 0;
foreach (var propertyInfo in propertiesInfo)
{
if (propertyInfo.CanRead && propertyInfo.Name != "Name")
{
var toCompareOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(toCompareOne).ToString();
var correctOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(this.CorrectOne).ToString();
int value = GetQuizValue(propertyInfo);
if (Comparer.Compare(toCompareOnePropertyValue, correctOnePropertyValue) == 0)//equals
{
result += value;
}
}
}
return result;
}
private int GetQuizValue(PropertyInfo propertyInfo)
{
var attributes = propertyInfo.GetCustomAttributes(typeof(QuizValue), false);
int value = this.QuizDefaultValue;
if (attributes != null && attributes.Count() > 0)
{
var quizValueAttribute = attributes[0];
if (quizValueAttribute is QuizValue)
{
var quizValue = quizValueAttribute as QuizValue;
value = quizValue.Value;
}
}
return value;
}
public QuizModel CorrectOne { get; set; }
public IComparer<string> Comparer { get; set; }
public int QuizDefaultValue { get; set; }
}
[System.AttributeUsage(System.AttributeTargets.Property)]
public class QuizValue : System.Attribute
{
public QuizValue(int value = 1)
{
this.Value = value;
}
public int Value
{
get;
set;
}
}
Please try like below, May this will leads you to get what you think
It will always compare the Quiz2 with the Quiz1 value.
public string Quiz1 {get; set;}
[CompareAttribute("Quiz1", ErrorMessage = "Quiz2 is mismatch with Quiz1")]
public string Quiz2 { get; set; }
this will give you wrong answers only:
var quiz = new QuizModel() { Name = "Quiz 1", Quiz1 = "Correct answer", Quiz2 = "Correct answer", Quiz3 = "Correct answer" };
var correctQuiz = new QuizModel() { Name = "Quiz 1", Quiz1 = "Correct answer", Quiz2 = "Wrong answer", Quiz3 = "Wrong answer 2" };
Func<QuizModel, List<string>> getListOfAnswers = (currentquiz) =>
(
from property
in typeof(QuizModel).GetProperties()
select property.Name + " " + property.GetValue(currentquiz)
).ToList();
var answers = getListOfAnswers(quiz);
var correctAnswers = getListOfAnswers(correctQuiz);
var wrongAnswers = correctAnswers.Except(answers);
output:
Quiz2 Wrong answer
Quiz3 Wrong answer 2
This solution is using Reflection, LINQ and Anonymous functions at once so it's very cool :)
Hello I have one List of data and I want to remove a data from list but my code return a error when I am deleting a value one time here is my code and classes
The error is
Collection was modified; enumeration operation may not execute. removing list item
boko_data_json ListAvailableData = Newtonsoft.Json.JsonConvert.DeserializeObject<boko_data_json>(json);
foreach (var item in ListAvailableData.data)
{
string PDFPath = item.downloadpdfpath;
string filename = lastPart.Split('.')[0];
int result = obj.getfile(filename);
if (result == 1)
{
ListAvailableData.data.Remove(item);
}
}
listnameAvailable.ItemsSource = ListAvailableData.data;
} public class boko_data_json
{
// public string Type { get; set; }
public List<Book> data{ get; set; }
public string downloadpdfpath { get; set; }
public string book_name { get; set; }
}
public class Book
{
public int book_id { get; set; }
public string book_name { get; set; }
public string issue_date { get; set; }
public string description { get; set; }
public string status { get; set; }
public string month { get; set; }
public int price { get; set; }
private string forprice { get { return "TL"; } }
public string showprice { get { return price +" "+forprice; } }
private string staticpath { get { return "http://dergiapp.net/"; } }
public string book_image { get; set;}
public string imagepath {get {return staticpath+book_image; }}
public string pdf_path { get; set; }
public string staticpdfpath { get { return "http://dergiapp.net/mobile/test.php?file="; } }
public string downloadpdfpath { get { return staticpdfpath + pdf_path; } }
private string Privewpadf1 { get { return "http://dergiapp.net/zip/p"; } }
private string Privewpadf2 { get { return ".zip"; } }
public string privewpdf { get { return Privewpadf1 + book_id + Privewpadf2; } }
public string download_status { get; set; }
}
You should use the List.RemoveAll() method to remove all the elements that match a particular predicate, as this code snippet illustrates:
List<string> strList = new List<string>()
{
"One",
"Two",
"RemoveMe",
"Three",
"Four"
};
strList.RemoveAll(element => element == "RemoveMe");
This removes all elements matching "RemoveMe".
If the predicate is quite complicated, you can put it into a separate method, like so:
strList.RemoveAll(shouldBeRemoved);
...
private static bool shouldBeRemoved(string element)
{
// Put whatever complex logic you want here,
// and return true or false as appropriate.
return element.StartsWith("Remove");
}
You can't remove an item from your list while your looping through its items. You're modifying the content of collection while there's a loop to enumerate it.
This is the reason of Collection was modified; enumeration operation may not execute. removing list item.
You should do the following:
boko_data_json copyList = ListAvailableData;
foreach (var item in ListAvailableData.data)
{
string PDFPath = item.downloadpdfpath;
string filename = lastPart.Split('.')[0];
int result = obj.getfile(filename);
if (result == 1)
{
copyList.data.Remove(item);
}
}
listnameAvailable.ItemsSource = copyList.data;
Another approach would be this:
boko_data_json itemsToRemove = new boko_data_json();
foreach (var item in ListAvailableData.data)
{
string PDFPath = item.downloadpdfpath;
string filename = lastPart.Split('.')[0];
int result = obj.getfile(filename);
if (result == 1)
{
itemsToRemove.data.Add(item);
}
}
foreach (var itemToRemove in itemsToRemove)
{
ListAvailableData.data.Remove(itemToRemove);
}
public class Item
{
public List<int> val { get; set; }
public double support { get; set; }
}
I declare variable:
List<Item> t = new List<Item>();
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
var b = new Item();
b.val = t[0].val;
b.support=t[0].support;
t.Contain(b) // return false???
I'm try with linq
t.Any(a=>a.val==b.val) // I'm get error Expression cannot contain lambda expressions
3 possibilities come to mind:
You could implement IEquatable<T>:
public class Item: IEquatable<Item>
{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item other)
{
return
this.support == other.support &&
this.val.SequenceEqual(other.val);
}
}
and now t.Contains(b) will return true.
If you cannot modify the Item class you could write a custom EqualityComparer:
public class ItemEqualityComparer : IEqualityComparer<Item>
{
private ItemEqualityComparer()
{
}
public static IEqualityComparer<Item> Instance
{
get
{
return new ItemEqualityComparer();
}
}
public bool Equals(Item x, Item y)
{
return
x.support == y.support &&
x.val.SequenceEqual(y.val);
}
public int GetHashCode(Item obj)
{
int hash = 27;
hash += (13 * hash) + obj.support.GetHashCode();
foreach (var item in obj.val)
{
hash += (13 * hash) + item.GetHashCode();
}
return hash;
}
}
and then t.Contains(b) will also return true.
Or if you prefer simply do it naively:
List<Item> t = new List<Item>();
t.Add(new Item { val = new List<int>(){1,2,3}, support=.1 });
var b = new Item();
b.val = t[0].val;
b.support = t[0].support;
bool equals = t.All(item => item.support == b.support && item.val.SequenceEqual(b.val));
Console.WriteLine(equals);
Your t.Any(a=>a.val == b.val) is correct.
The error you get is from the quick watch or expression window in the debugger, not from the compiler. Visual Studio's expression evaluator does not handle lambdas. However, it's still valid c# code, and will do what you want.
It's your earlier line that's a problem:
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
This is a mixture of various different bits of syntax. It should be:
t.Add(new Item(){val = new List<int>(){1,2,3}, support=.1});
... although preferably with better property names, etc. Then the rest should work - although you need to do something with the result of Any. The Any call itself is valid. Here's a short but complete program which works:
using System;
using System.Collections.Generic;
using System.Linq;
public class Item
{
public List<int> Values { get; set; }
public double Support { get; set; }
}
class Test
{
static void Main()
{
List<Item> list = new List<Item>
{
new Item { Values = new List<int>{1, 2, 3},
Support = 0.1 }
};
var check = new Item { Values = list[0].Values,
Support = list[0].Support };
bool found = list.Any(a => a.Values == check.Values);
Console.WriteLine(found);
}
}
Note that this is performing a reference comparison between the two lists - if you created a different list with the same values (1, 2, 3), that wouldn't be found. You'd need to use a.Values.SequenceEqual(b.Values) or something similar.
Your Item class should implemenet the IEquatable interface:
class Item : IEquatable<Item>{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item item){
return this.support.Equals(item.support) && this.val.SequenceEqual(item.val);
}
}
Then the Contains() method should work well.
You can correct your "t.Contain(b)" to t.Contains(b, new ItemEqualityComparer()) from System.Linq where ItemEqualityComparer will be your class, which will implement IEqualityComparer<Item>
Hi I have had to use interfaces before but ive been told i need to implement icomparable in this instance. see below:
internal class doorItem : IComparable
{
public int CompareTo(doorItem other)
{
// The temperature comparison depends on the comparison of the
// the underlying Double values. Because the CompareTo method is
// strongly typed, it is not necessary to test for the correct
// object type.
return GetNumber(productSize).CompareTo(GetNumber(other.productSize));
}
public string variations { get; set; }
public double pricerange { get; set; }
public string viewDetailsLink { get; set; }
public string height { get; set; }
public string width { get; set; }
public string productSize { get; set; }
public string productImage { get; set; }
public int countItemsOnSale { get; set; }
public string optionFor35Product { get; set; }
private int GetNumber(string str)
{
//this method gets the int out of the string
int length = str.Length;
string output = String.Empty;
int test = 0;
bool err = false;
for (int i = 0; i <= length; i++)
{
try
{
test = Convert.ToInt32(str.Substring(i, 1));
}
catch
{
err = true;
}
if (!err)
output += str.Substring(i, 1);
else
break;
}
return Convert.ToInt32(output);
}
}
above is the class i have created, door sizes are returned like this: 4dr, 5dr, 6dr etc.. then the getnumber method gets the int out of the string.
i have a generic list in of my custom class in the main method like this:
List<doorItem> d = new List<doorItem>();
i cant work out how to order this list by door size.... PLEASE HELP
It's easiest to do this using LINQ. Then you don't even need to implement IComparable.
var sortedList = doorList.OrderBy( d => d.GetNumber(d.productSize ).ToList();
And make GetNumber public inside the doorItem class.
I don't know if performance is important, but that method for getting the number is pretty horrible, exceptions should only be used in exceptional circumstances! Suggest something like this
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (Char.IsNumber(c))
{
sb.append(c);
}
}
return Convert.ToInt32(sb.ToString());
For sorting you can do what stecya has suggested, or you could convert this method to a property and sort directly.
public int Size
{
get
{
return GetNumber(this.productSize);
}
}
...
d.OrderBy(x=>x.Size);