Retrieve a Customized String Value - c#

Goal:
Retrieve a string value that is "1_2_3" om the code myListAnimals. In the future, the value can be random.
I need to add a "_" between numbers.
Problem:
I don't know how to do it by using LINQ?
public class Animal
{
private void int _number;
private void string _name;
private bool display;
public int Number
{
get { return _number;}
set { _number = value; }
}
public int Name
{
get { return _name;
set { _name = value; }
}
public bool Display
{
get { return display;
set { display = value; }
}
}
List<Animal> myListAnimal = new List<Animal>
Animal myAnimal = new List<Animal>
myAnimal.Number = 1;
myAnimal.Name = "Dog";
myAnimal.Display = True;
myAnimals.add(myAnimal )
Animal myAnimal2 = new List<Animal>
myAnimal2.Number = 2;
myAnimal2.Name = "Cat";
myAnimal2.Display = True;
myAnimals.add(myAnimal2)
Animal myAnimal3 = new List<Animal>
myAnimal3.Number = 3;
myAnimal3.Name = "Pig";
myAnimal3.Display = True;
myAnimals.add(myAnimal3)
Animal myAnimal4 = new List<Animal>
myAnimal4.Number = 4;
myAnimal4.Name = "Sheep";
myAnimal4.Display = false;
myAnimals.add(myAnimal4)

Note: Your code sample isn't valid C#. I assume that you can fix that (it's pretty simple basic changes that need to be made). That said:
Yes, you can use LINQ to concatenate strings, which is ultimately what you're doing.
var concat = myListAnimal
.Where(a => a.Display)
.Select(a => a.Number.ToString())
.Aggregate((current, next) => current + "_" + next);
Console.WriteLine(concat);
Would output with your data:
1_2_3
Where() filters the values where Display != true
Select() projects the number values to a sequence of strings
and Aggregate() does the concatenation.

your code is not valid. First fix it and try this.
var concat =string.Join("_", myListAnimal.Select(a => a.Number).ToArray());

Try using StringBuilder and ForEach extension method.
StringBuilder sb = new StringBuilder();
myAnimals.ForEach(x=> sb.AppendFormat("{0}_",x.Number));

Related

C# LINQ statement

I have two lists; List<int> numList has identifier number as its elements, and List<string> filePaths has path to file that needs to be analyzed as its elements. I want to filter filePaths based on the numList; that is, I only want to select the filePaths whose file names have the identifier number that is present in the numList.
For example, filePaths has
C:/test/1.test.xlsx
C:/test/2.test.xlsx
C:/test/3.test.xlsx
C:/test/4.test.xlsx
and, numList has
1
2
In this case, I want to construct LINQ statement to only get
C:/test/1.test.xlsx
C:/test/2.test.xlsx
I tried
for(int i = 0; i < numList.Count; i++)
{
filePaths = filePaths.Where(f => Convert.ToInt32(GetNumberFromString(Path.GetFileName(f))) == numList[i]).ToList();
}
And this is GetNumberFromString Helper Method
// Find number in the string
private string GetNumberFromString(string value)
{
int number;
string resultString = Regex.Match(value, #"\d+").Value;
if (Int32.TryParse(resultString, out number))
{
return resultString;
}
else
{
throw new Exception(String.Format("No number present in the file {0}", value));
}
}
I think this will work, but is there more elegant/efficient way of achieving this?
You can do it with a one-liner:
var filteredFilePaths = filePaths.Where(x => numList.Contains(GetNumberFromString(x));
I'd do it like this. The test method assumes that all the files in directory have appropriately formatted names. If that's not a reasonable assumption, it's easy enough to fix.
This is overkill, however, if you only ever care about the "file number" in one place.
public class TestClass
{
public static void TestMethod(String directory)
{
var files = System.IO.Directory.GetFiles(directory).Select(f => new FileInfo(f)).ToList();
var numList = new[] { 1, 2 };
var oneAndTwo = files.Where(fi => numList.Contains(fi.FileNumber)).ToList();
}
}
public class FileInfo
{
public FileInfo()
{
}
public FileInfo(String path)
{
Path = path;
}
public int FileNumber { get; private set; }
private string _path;
public String Path
{
get { return _path; }
set
{
_path = value;
FileNumber = GetNumberFromFileName(_path);
}
}
public static int GetNumberFromFileName(string path)
{
int number;
var fileName = System.IO.Path.GetFileName(path);
string resultString = Regex.Match(fileName, #"\d+").Value;
if (Int32.TryParse(resultString, out number))
{
return number;
}
else
{
throw new Exception(String.Format("No number present in the file {0}", path ?? "(null)"));
}
}
}
A stand-alone One-liner using a Join :
var result = filePaths.Select(x => new { Filename = Path.GetFileName(x), x })
.Join(numList, x => Regex.Match(x.Filename, "^([0-9]+)").Value,
y => y.ToString(),
(x, y) => x.x);

Using enum item to call a method

I have an enum with 30 items in it. Each item has a corresponding function with the same name. I would like to be able to call the function by referencing the enum at a certain position.
So if the value at enum[0] = Foo, I would like to be able to call Foo(string bar) by using something like enum(0)("foobar")
In the end the point is I am running each function as a task like so:
enum Test { AA, BB, CC, DD ....}
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); });
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); });
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); });
//for 30 tasks
What I would like to do is something along the lines of:
enum Test { AA, BB, CC, DD ....}
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); });
}
Task.WaitAll(tasks.ToArray());
Is this something that is even possible?
EDIT:
The enum relates to controls on a form so i have an array of textboxs, label and a array of prices that is populated with the results of the functions:
enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 };
static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length;
decimal[] prices = new decimal[noOfDealers];
TextBox[] textBox = new TextBox[noOfDealers];
Label[] boxes = new Label[noOfDealers];
for (int i = 0; i < noOfDealers; i++)
{
textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox;
boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label;
prices[i] = 0;
}
//RUN 30 TASKS TO POPULATE THE PRICES ARRAY
for (int i = 0; i < noOfDealers; i++)
{
textBox[i].Text = "£" + prices[i].ToString();
}
//LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS
I guess i am just trying to make my code as concise as possible, there is the potential for the amount of tasks to double and didn't want to end up with 60 lines to populate the tasks array
I would create dictionary and map enum to actions:
Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>()
{
{Test.AA, (x) => { return 5;}},
{Test.BB, (x) => { return 15; }},
}; //x is your string
var res = actions[Test.AA]("hello");
I would strongly suggest using a built in construct - like an extension method and a simple switch:
public static int GetPriceWithString(this Test test, string str)
{
switch (test)
{
case Test.AA:
break;
case Test.BB:
break;
case Test.CC:
break;
case Test.DD:
break;
default:
throw new ArgumentOutOfRangeException(nameof(test), test, null);
}
}
then your loop looks almost the same:
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() =>
{
prices[i] = ((Test)i).GetPriceWithString("a string");
});
}
What you want to do is possible with reflection, which can be a powerful tool - but ideally should only be used as a last resort, as it will hide what could be compile time errors, and cause less code readability.
Using a simple switch like this makes your code self-documented, so when you come back to this in a month you can quickly remember what the intention was.
How about using an array of delegates:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
private static int AA(string a) { return 0; }
private static int BB(string a) { return 1; }
private static int CC(string a) { return 2; }
private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC };
private static int[] prices = new int[functions.Length];
private static Task[] tasks = new Task[functions.Length];
static void Main(string[] args)
{
for (int i = 0; i < functions.Length; ++i)
tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); });
Task.WaitAll(tasks);
}
}
}
An eg. speaks a lot more than words.
I used it in a winform so the this refers to win form.
I have assumed all your methods are public , have same signature & return the same type.
enum MyName { AA,BB,CC};
//Call this in one of your methods
string [] strVal= Enum.GetNames(typeof(MyName));
int x = CallFunction(strVal[0], "A");
int y = CallFunction(strVal[1], "h");
int z = CallFunction(strVal[1], "C");
//End Call this in one of your methods
int CallFunction(string strName,string strValue)
{
return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue }));
}
public int AA(string s)
{
return 1;
}
public int BB(string s)
{
return 2;
}
public int CC(string s)
{
return 3;
}
Another solution. I hope somebody will consider it as overkill :)
Create abstract class DealerBase.
public abstract class DealerBase
{
public string Name { get; }
public decimal Price { get; set; }
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
}
Then create classes for every dealers you have and implement own logic for UpdatePrice method.
public class Dealer1 : DealerBase
{
public Dealer1() : base("DealerOne") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerOneCalculationMethod();
}
}
public class Dealer2 : DealerBase
{
public Dealer2() : base("DealerTwo") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerTwoCalculationMethod();
}
}
And so on..
Then you just create collection of dealers which can be easily iterated
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
}
foreach(var dealer in dealers)
{
dealer.UpdatePrice();
}
You can loop dealers and generate textboxes, labels in the winforms.
But I suggest to use DataGridView where code will be tiny clearer.
First implement INotifyPropertyChanged interface in the base class DealerBase
public abstract class DealerBase : INotifyPropertyChanged
{
public string Name { get; }
protected decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
if (Equals(_Price, value)) return;
_Price = value;
// next method will inform DataGridView about changes
// and update value there too
RaisePropertyChanged();
}
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
The in the Form you can create BindingList<DealerViewModelBase> and set it to DataGridView.DataSource
public class YourForm: Form
{
public YourForm()
{
InitializeComponent();
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
};
var bindSource = new BindingList<DealerBase>(dealers);
dataGridView.DataSource = bindSource;
}
// Add button which update prices for all dealers
private void ButtonUpdatePrices_Click(object sender, EventArgs e)
{
var dealers = (BindingList<DealerBase>)dataGridView.DataSource;
foreach (var dealer in dealers)
{
dealer.UpdatePrice();
// Because we call `RaisePropertyChanged` in
// setter of Price - prices will be automatically
// updated in DataGridView
}
}
}
Idea of this approach you put different logic of different dealers in the separated class which. Because all dealer classes will inherit from same abstract class you can add different dealers to the collection.
You already have hardcoded enums and correspondent method which you try to link together. This approach make using of dealers collection little bid easy

Luatable equivalent in C#?

I've been looking for a way to make a table like thing in C# (3.5), but still have come up empty. Basically I want to do this
var myClassVar = new myClass();
myClassVar["hello"]["world"] = "hello world";
myClassVar["hello"][0] = "swapped";
myClassVar[0][0] = "test";
myClassVar["hello"]["to"]["the"]["world"] = "again";
myClassVar[0][1][0][0] = "same as above sorta";
I'm trying to create this type of class to parse a file format I've created for storing data. Does anyone know of something like this?
public class LuaTable
{
private Dictionary<object, dynamic> properties = new Dictionary<object, dynamic>();
public dynamic this[object property]
{
get
{
if (properties.ContainsKey(property))
return properties[property];
LuaTable table = new LuaTable();
properties.Add(property, table);
return table;
}
set
{
if (!properties.ContainsKey(property))
properties.Add(property, value);
else
properties[property] = value;
}
}
}
You can use it exactly how you want to:
var myClassVar = new LuaTable();
myClassVar["hello"]["world"] = "hello world";
myClassVar["hello"][0] = "swapped";
myClassVar[0][0] = "test";
myClassVar["hello"]["to"]["the"]["world"] = "again";
myClassVar[0][1][0][0] = "same as above sorta";
string s1 = myClassVar["hello"]["world"]; // = "hello world"
string s2 = myClassVar["hello"][0]; // = "swapped"
string s3 = myClassVar[0][0]; // = "test"
string s4 = myClassVar["hello"]["to"]["the"]["world"]; // = "again"
string s5 = myClassVar[0][1][0][0]; // = "same as above sorta"
Edit: I just realized C# 3.5 doesn't have dynamic, so here's a version that simply uses generics. I hope that this is fine (since you really have to have all of the child properties of your table be of the same type (in this case, string):
public class LuaTable<T> where T : class
{
private bool isValue;
private T value = null;
private Dictionary<object, LuaTable<T>> properties = new Dictionary<object, LuaTable<T>>();
public static implicit operator LuaTable<T>(T val)
{
if (val is LuaTable<T>)
return (LuaTable<T>)val;
return new LuaTable<T>() { isValue = true, value = val };
}
public static implicit operator T(LuaTable<T> table)
{
if (table.isValue)
return table.value;
return table;
}
public LuaTable<T> this[object property]
{
get
{
if (isValue)
return null;
if (properties.ContainsKey(property))
return properties[property];
LuaTable<T> table = new LuaTable<T>();
properties.Add(property, table);
return table;
}
set
{
if (!properties.ContainsKey(property))
properties.Add(property, value);
else
properties[property] = value;
}
}
}
To use it, it's almost exactly the same as above. Just change the first line:
var myClassVar = new LuaTable<string>();

Getting empty List by converting properties into List

I have the following property Class:
public class Ctas
{
private string _CodAgrup;
public string CodAgrup
{
get { return _CodAgrup; }
set { _CodAgrup = value; }
}
private string _NumCta;
public string NumCta
{
get { return _NumCta; }
set { _NumCta = value; }
}
private string _Desc;
public string Desc
{
get { return _Desc; }
set { _Desc = value; }
}
private string _subctade;
public string SubCtaDe
{
get { return _subctade; }
set { _subctade = value; }
}
private string _Nivel;
public string Nivel
{
get { return _Nivel; }
set { _Nivel = value; }
}
private string _Natur;
public string Natur
{
get { return _Natur; }
set { _Natur = value; }
}
public override string ToString()
{
return "CodAgrup = " + CodAgrup + ", NumCta = " + NumCta + ", Desc = " + Desc + ", SubCtaDe = " + SubCtaDe + ", Nivel = " + Nivel + ", Natur = " + Natur;
}
#endregion
}
and I have Create an XML from these properties, so first I have to fill the properties, then i got the next method i want to use to fill the properties, first question is, is it correct the way Im using to fill the properties?
Then I should retreive the data and write it on an XML file so I convert properties data into a list and then just write them as atributes but when i Debug, I get that the list is empty, Why is that? what could be the best way to do it?
//Insert n data on properties
static void cuenta(string codagroup, string numcta, string desc, string subctade, string nivel, string natur)
{
Ctas cuentas = new Ctas();
int x = 0;
while (cuentas.CodAgrup != null)
{
cuentas.CodAgrup.Insert(x, "codagroup");
cuentas.NumCta.Insert(x, "numcta");
cuentas.Desc.Insert(x, "desc");
cuentas.SubCtaDe.Insert(x,"subctade");
cuentas.Nivel.Insert(x, "nivel");
cuentas.Natur.Insert(x, "natur");
x = x + 1;
}
}
//Converting propierties data into list
List<string> coda = cuentas.CodAgrup.GetType().GetProperties().Select(p => p.Name).ToList();
List<string> ncta = cuentas.NumCta.GetType().GetProperties().Select(p => p.Name).ToList();
List<string> desc = cuentas.Desc.GetType().GetProperties().Select(p => p.Name).ToList();
List<string> subdes = cuentas.SubCtaDe.GetType().GetProperties().Select(p => p.Name).ToList();
List<string> nivel = cuentas.Nivel.GetType().GetProperties().Select(p => p.Name).ToList();
List<string> natur = cuentas.Natur.GetType().GetProperties().Select(p => p.Name).ToList();
//Create XML from data in list´s
for (int i = 0; i < coda.Count; i++)
{
xmlWriter.WriteAttributeString("CodAgrup", coda[i]);
xmlWriter.WriteAttributeString("NumCta", ncta[i]);
xmlWriter.WriteAttributeString("Desc", desc[i]);
//write the atribute when property data exists.
if (cuentas.SubCtaDe != null)
{
xmlWriter.WriteAttributeString("SubCtaDe", subdes[i]);
}
xmlWriter.WriteAttributeString("Nivel", nivel[i]);
xmlWriter.WriteAttributeString("Natur", natur[i]);
xmlWriter.WriteEndElement();
}
Your code is confusing, but if I understand it right, here is the first error I see:
Ctas cuentas = new Ctas();
int x = 0;
while (cuentas.CodAgrup != null) // cuentas.CodAgrup is null from the beginning!
{
cuentas.CodAgrup.Insert(x, "codagroup");
cuentas.NumCta.Insert(x, "numcta");
cuentas.Desc.Insert(x, "desc");
cuentas.SubCtaDe.Insert(x,"subctade");
cuentas.Nivel.Insert(x, "nivel");
cuentas.Natur.Insert(x, "natur");
x = x + 1;
}
Since you are looking at a brand-new Ctas object, and there is no code to initialize the CodAgrup property, it will have the default value of null, so the code never enters the while loop.
Even if it DID, I suspect it would be an endless loop, because you're Inserting a literal value into a string property, and there is no condition I see where cuentas.CodAgrup will ever be null.
As for your XML generation, why not just use the built in XmlSerializer class? Even if you require a specific format, there are attributes that let you customize the XML that is generated.

C# Find Index of a List of Classes

Finding an Index of a Class:
The only way I know to find an index of List is
int index = listEmployee.FindIndex(
delegate(Employee findEmployee)
{
return findEmployee.Name.Equals(findName, StringComparison.Ordinal);
});
I was wondering how to add the option to use
int indexT = listEmployee.FindIndex(r >= r.Name == findName);
Or basically what I'm doing wrong that I can't use it.
class Employee
{
private string _name; private int _idNumber;
private string _deptarment; private string _position;
public Employee()
{
_name = ""; _idNumber = 0; _deptarment = ""; _position = "";
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public int IdNumber
{
get { return _idNumber; }
set { _idNumber = value; }
}
public string Department
{
get { return _deptarment; }
set { _deptarment = value; }
}
public string Position
{
get { return _position; }
set { _position = value; }
}
}
I was wondering how to add the option to use
int indexT = listEmployee.FindIndex(r >= r.Name == findName);
That's fine, apart from the syntax problem at r >= which should be r =>
So this works:
int indexT = listEmployee.FindIndex(r => r.Name == findName);
See: Lambda Expressions
int indexT = listEmployee.FindIndex(r => r.Name == findName);
should work. Perhaps you are missing the using System.Linq referece
Not entirely sure what you're trying to accomplish, but a simple List collection is not going to ensure order or sort, so the index (especially if the collection is going to be expected to change) is not a reliable means of accessing a specific object.
If index / order is important, maybe look at a different collection type, such as the Sorted list: http://msdn.microsoft.com/en-us/library/system.collections.sortedlist.aspx
If you're just trying to find a specific object, you can use Linq and just go something like:
listEmployee.Where( r => r.Name == findName );

Categories

Resources