I have a question about the following code:
private void Filter (object sender, Android.Text.TextChangedEventArgs e)
{
List<Animal> animalList = new List<Animal>();
if(!string.IsNullOrEmpty(_editText.Text))
{
foreach (string str in _animalList)
{
if (str.Contains(_editText.Text))
{
animalList.Add (str);
}
}
}
_listView.Adapter = new AnimalAdapter(this, _animalList = animalList);
}
The Animal class:
public class Animal
{
private readonly int _intKey;
public int AnimalNumber { get; private set; }
public int StableNumber { get; private set; }
public int LactoseNumber { get; private set; }
public Animal ( int intKey, int animalNumber, int stableNumber, int lactoseNumber )
{
_intKey = intKey;
AnimalNumber = animalNumber;
StableNumber = stableNumber;
LactoseNumber = lactoseNumber;
}
public override string ToString ()
{
return "Number: " + AnimalNumber + "\nGroup: " + StableNumber + "\nLactation: " + LactoseNumber;
}
}
Declaration of _animalList:
private List<Animal> _animalList;
i need to check if the _animalList Contains the input of the _editText.Text.
But _animalList isn't a string so i need to use a var.
Is there something like a var.Contains or do i have to use something else?
Contains method is available for string type. You will need to cast your object to string.
A/c to your class definition you should do like:
foreach (Animal str in _animalList)
{
if (str.ToString().Contains(_editText.Text)) //using user defined "ToString()"
{
animalList.Add (str);
}
}
You can also check individual properties:
foreach (Animal str in _animalList)
{
if (str.AnimalNumber.ToString().Contains(_editText.Text)) //if "AnimalNumber" is like "_editText.Text"
{
animalList.Add (str);
}
}
Instead of trying to filter using ToString, it would be better to use the real property values. For example:
var number = Convert.ToInt32(_editText.Text);
var filteredList = _animalList
.Where(x => x.AnimalNumber == number ||
x.StableNumber == number ||
x.LactoseNumber == number)
.ToList();
Otherwise, user could type "Number" and since your ToString override contains that string, all of the items in the list would match positively.
(I didn't include any validation or error checking in the code above, so you should consider those as well).
var inputText = _editText.Text;
int enteredNumber;
// you should make sure that the inputText is always an int
var isInt = int.TryParse(inputText, out enteredNumber);
//for example, if you are going to find by AnimalNumber, which is an int, you can use this. .
if (isInt){
foreach (var animal in _animalList){
var animalNumber = animal.AnimalNumber;
if (animalNumber == enteredNumber)
{
animalList.Add(animal);
}
}
}
Edit (LINQ alternative):
if (isInt){
animalList.AddRange(from animal in _animalList
let animalNumber = animal.AnimalNumber
where animalNumber == enteredNumber
select animal);
}
_animalList.Select(a => a.ToString()).Contains(_editText.Text)
This expression returns true if the output of the ToString method of any animal object equals _editText.Text.
_animalList.Select(a => a.ToString()).Any(str => str.Contains(_editText.Text))
This expression returns true if the output of the ToString method of any animal object contains _editText.Text (as a substring). This is equivalent to Shaharyar's answer.
var animalList = _animalList.Where(a => a.ToString().Equals(_editText.Text)).ToList();
var animalList = _animalList.Where(a => a.ToString().Contains(_editText.Text)).ToList();
These statements filter the input list directly.
Related
I have the following list of strings :
var files = new List<string> {"file0","file1","file2","file3" };
I would like to be able to add new files to this list, but if the inserted file is present in the list, I would like to insert custom value that will respect the following format $"{StringToBeInserted}"("{SomeCounter}
For instance : try to add "file0" and "file0" is already I would like to insert "file0(1)". If I try again to add "file0" ... I would like to insert with "file0(2)" and so on ... Also, I would like to provide a consistency, for instance if I delete "file0(1)" ... and try to add again "item0" ... I expect that "item0(1)" to be added. Can someone help me with a generic algorithm ?
I would use a HashSet<string> in this case:
var files = new HashSet<string> { "file0", "file1", "file2", "file3" };
string originalFile = "file0";
string file = originalFile;
int counter = 0;
while (!files.Add(file))
{
file = $"{originalFile}({++counter})";
}
If you have to use a list and the result should also be one, you can still use my set approach. Just initialize it with your list and the result list you'll get with files.ToList().
Well, you should create your own custom class for it, using the data structure you described and a simple class that includes a counter and an output method.
void Main()
{
var items = new ItemCountList();
items.AddItem("item0");
items.AddItem("item1");
items.AddItem("item2");
items.AddItem("item0");
items.ShowItems();
}
public class ItemCountList {
private List<SimpleItem> itemList;
public ItemCountList() {
itemList = new List<SimpleItem>();
}
public void DeleteItem(string value) {
var item = itemList.FirstOrDefault(b => b.Value == value);
if (item != null) {
item.Count--;
if (item.Count == 0)
itemList.Remove(item);
}
}
public void AddItem(string value) {
var item = itemList.FirstOrDefault(b => b.Value == value);
if (item != null)
item.Count++;
else
itemList.Add(new SimpleItem {
Value = value,
Count = 1
});
}
public void ShowItems() {
foreach (var a in itemList) {
Console.WriteLine(a.Value + "(" + a.Count + ")");
}
}
}
public class SimpleItem {
public int Count {get; set;}
public string Value {get; set;}
}
I have a class that contains a list of another class which has a property that I want to check if it has more than one distinct value.
e.g
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
.
.
.
public class BasketOrderLine
{
public int OrderLineId { get; set; }
public string ImageUrl { get; set; }
public string ProductType { get; set; }
.
.
Given a basket model object I want to find out if there are more than one distinct value in the ProductType.
e.g If all Product Types are "A" then that would be false, if 3 products are of type "A" and one is of type "B" then this would be true.
Cheers
Macca
Your title: "more than two distinct", your question body: "more than one distinct"
If the title is a typo:
bool notDistinctTypes = theBasket.BasketOrderLine
.Select(o => o.ProductType)
.Distinct()
.Skip(1)
.Any();
This doesn't need to enumerate all items to find out if there is more than one ProductType.
// Does this basket contains three or more types
public bool HasSeveralTypes(BasketModel basket)
{
if (basket == null)
return false;
int differentTypes = basket.BasketOrderLines
.Select(l => l.ProductType)
.Distinct()
.Count();
return (differentTypes > 2);
}
Something like this :
Public bool CheckDistinct (){
var res = basketOrderLines.Select(o => o.ProductType).Distinct ().Count ();
return res > 1;
}
There are a few ways to do this, here's one:
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
public bool HasMulitpleDistinctProducts
{
get
{
if (!BasketOrderLines.Any())
{
return true; // or false?
}
return BasketOrderLines.Select(b => b.ProductType).Distinct().Count() > 1;
}
}
}
Here is a type extension you can call directly from your list. The pros of this code is to be adaptable to any type implementing IEquals and not only string + kick to use from your code.
The code :
public static class Tools
{
public static bool fDistinctProductType(this List<BasketOrderLine> lstToAnalyse)
{
BasketOrderLine ProductTypeA = lstToAnalyse.FirstOrDefault();
if (ProductTypeA == null) // It's null when lstToAnalyse is empty
return false;
BasketOrderLine ProductTypeB = lstToAnalyse.Where(b => b.ProductType.Equals(ProductTypeA.ProductType)).FirstOrDefault();
if (ProductTypeB == null) // It's null when it doesn't exists a distinct ProductType
return false;
return true;
}
}
How to call:
List<BasketOrderLine> lst = new List<BasketOrderLine>();
// Add element to list
if (lst.fDistinctProductType())
{
// DO Something
}
I have two variables that contain true/false data. THe first variable can be null but the second variable is always non null. Both variables will always be the same length.
var AnswerGridCorrect = "000111"; // or null
var AnswerGridResponses = "000011";
How could I change this data into an object oriented form. I already created classes and these are below. Here's is what I need the output to look like when converted to JSON:
"answers":[ // Json conversion made Answers into answers
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":false}
}
Note that I am using LINQ to output the data so I think what I need is a function with parameters something like this:
.Select((t, index) => new {
Answer = t.Answer,
Answers = makeAnswer(t.AnswerGridCorrect,
t.AnswerGridResponses)
});
I am not sure if this helps but here were the classes I was using when I did this from JSON:
public class AnswerRow
{
public bool? Correct { get; set; }
public bool Response { get; set; }
}
public class AnswerRowList
{
public IList<AnswerRow> AnswerRows { get; set; }
}
Here is an implementation for your makeAnswers method:
public List<AnswerRow> makeAnswers(string c, string r)
{
var result = new List<AnswerRow>();
for(var i=0; i<r.Length; i++)
{
result.Add(
new AnswerRow {
Correct = c!=null?new Nullable<bool>(c[i]=='1'):null,
Response = r[i]=='1'
});
}
return result;
}
Rene's answer is probably correct, but here's the (unnecessarily complex) Linq way:
AnswerRowList MakeAnswer(string answerGridCorrect, string answerGridResponses)
{
return new AnswerRowList()
{
AnswerRows = answerGridResponses.Zip(
answerGridCorrect == null ?
Enumerable.Repeat<bool?>(null, answerGridResponses.Length) :
answerGridCorrect.Select(x => new Nullable<bool>(x == '1')),
(r, c) => new AnswerRow()
{
Correct = c,
Response = r == '1'
}).ToList()
};
}
I have a base class called BaseStatus which looks like this:
public class BaseStatus
{
public int UnitId { get; protected set; }
public UInt16 StatusValue { get; protected set; }
public string StatusCode { get; protected set; }
public string StatusDescription { get; protected set; }
public BaseStatus()
{
this.UnitId = -1;
this.StatusValue = 0;
this.StatusCode = null;
this.StatusDescription = null;
}
}
Furthermore i have two or more other base classes which derive from BaseStatus and define a other unit id. For example the two classes
public class BaseGlobalStatus : BaseStatus
{
public BaseGlobalStatus()
{
base.UnitId = -1;
}
}
public class BaseGcmGdmStatus : BaseStatus
{
public BaseGcmGdmStatus()
{
base.UnitId = 2;
}
}
public class BaseCcuStatus : BaseStatus
{
public BaseCcuStatus()
{
base.UnitId = 1;
}
}
The Background is that i want to derive from for example BaseCcuStatus and have the correct UnitId in the derived class.
Now i define my correct status classes for example:
public class StatStErrDefinition : BaseGlobalStatus
{
public StatStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
public class GcmStErrDefinition : BaseGcmGdmStatus
{
public GcmStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
public class CcuStErrDefinition : BaseCcuStatus
{
public CcuStErrDefinition()
: base()
{
base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
base.StatusCode = "STAT_ST_ERR";
base.StatusValue = 3;
}
}
For my understading, the three classes StatStErrDefinition, GcmStErrDefinition and CcuStErrDefinition should have the UnitId which is set in the derived BaseClass?
Now that i have defined my three Status Classes i want to get them into a registry. Currently im using this piece of code to try get them. Problem is that the result has no items.
registry = new StatusDictionary<UInt16, BaseStatus>();
var unitStatus = typeof(BaseStatus)
.Assembly.GetTypes()
.Where(x => x.BaseType == typeof(BaseStatus))
.Select(x => new
{
StatusType = x,
UnitId = x.GetProperty("UnitId", BindingFlags.Public)
StatVal = x.GetProperty("StatusValue", BindingFlags.Public)
}
)
.Where(x => x.StatVal != null && x.UnitId != null)
.Select(x => new
{
UnitId = (int)x.UnitId.GetValue(null, null),
StatusValue = (UInt16)x.StatVal.GetValue(null, null),
Factory = (Func<BaseStatus>)(() => ((BaseStatus)Activator.CreateInstance(x.StatusType)))
});
try
{
foreach (var status in unitStatus)
{
if (status.UnitId == unitId
|| status.UnitId < 0)
registry.Register(status.StatusValue, status.Factory);
}
}
catch (Exception ex)
{
string temp = ex.Message;
}
After the LINQ expression the var unitStatus is empty...
Later, the registry call looks like that to get the specific class but that is unimportant at this point:
stat = StatusContainer.GetRegistry(this.unitTypeId).GetInstance(this.StatusValue);
For information:
I want to get the status class which should be in the registry by the unittypeid and the specific status value.
Currently my registry method does not work because he is not able to find any class. So there has to be a mistake somewhere. Thanks in advance
#Update 1
I changed my functionality a little bit:
registry = new StatusDictionary<UInt16, BaseStatus>();
//get all types of cucrent assembly
var allAssemblyTypes = Assembly.GetCallingAssembly().GetTypes();
//get all types from base status
var baseStatusTypes = allAssemblyTypes.Where(x => x.BaseType == typeof(BaseStatus));
//Place all concrete types in the foundtypes
List<Type> foundTypes = new List<Type>();
foreach (Type item in baseStatusTypes)
{
var temp = allAssemblyTypes.Where(x => x.BaseType == item)
.Select(x => new
{
StatusType = x,
UnitId = x.GetProperty("UnitId", BindingFlags.Public),
StatVal = x.GetProperty("StatusValue", BindingFlags.Public),
}
);
}
Temp contains now the correct type.
Problem is that if temp is type of StatStErrDefinition the StatusValue and UnitId Property is null.
The fact is that these members are instance members. Is there a way to get the values out of them?
First thing first : your LINQ query is pretty long.
divide it in different step and store them in different variables (or make properties out of them, whatever you prefer)
This is
easy to read / maintain
easy to debug
With this given I think you are able to solve your problem :)
To check if the class is of a certain type you could use the method .OfType
Use this method to get the value. Notice that you must make an instance in your case because the value change in your constructor.
public static object GetPropValue(Type src, string propName)
{
var prop = src.GetProperty(propName);
var instance = Activator.CreateInstance(src);
var value = prop.GetValue(instance);
return value;
}
Instead of
UnitId = x.GetProperty("UnitId", BindingFlags.Public),
use
UnitId = GetPropValue(x,"UnitId"),
How do I find and replace a property using Linq in this specific scenario below:
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
//TODO: Just copying values... Find out how to find the index and replace the value
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
Thanks for helping out in advance.
Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.
// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);
if (index != -1)
{
this.Properties[index] = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
Why are Array.Sort() and Array.IndexOf() methods static?
Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.
this.Properties[name] = value;
Note that neither solution is thread safe.
An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.
this.Properties = Enumerable.Union(
this.Properties.Where(p => p.Name != name),
Enumerable.Repeat(value, 1)).
ToArray();
[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(]
Is your 'Property' a class or a struct?
This test passes for me:
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
[TestMethod]
public void TestMethod1()
{
var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
Assert.AreEqual("Y", pb["X"].Value);
pb["X"] = new Property { Name = "X", Value = "Z" };
Assert.AreEqual("Z", pb["X"].Value);
}
I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.