Output an ordered collection (using LINQ) into a listbox - c#

I want to order a text file using LINQ by date and output all columns into a listbox.
For example the input file is:
Name,Age,DOB,Male
Mary,28,01/01/1991,False
Anne,29,06/06/1989,False
John,18,06/07/2000,True
class Name
{
public double Age { get; set;}
public string Name{ get; set; }
public DateTime Date { get; set; }
public string Male { get; set; }
public Name()
{
}
public Name(string name, double age, DateTime date, string male)
{
Course = course;
Amount = amount;
Date = date;
Male = male;
}
}
private IEnumerable<Name> ReadName()
{
List<Name> dataCollection = new List<Name>();
using (var f = new StreamReader(#"R:\Data.txt"))
{
string line = string.Empty;
while ((line = f.ReadLine()) != null)
{
var data = line.Split(',');
dataCollection.Add(new Name(data[0], Convert.ToDouble(data[1]),Convert.ToDateTime(data[2]), data[3]));
}
}
return dataCollection;
}
private void btnDOBOrder_Click(object sender, EventArgs e)
{
lstByDate.Items.Clear();
IEnumerable<Name> names = ReadName();
var DateOrder = name
.OrderByDescending(x => x.Date)
.ToList();
lstByDate.DataSource = DateOrder;
}
Name Age DOB Male
John 18 06/07/2000 True
Mary 28 01/01/1991 False
Anne 29 06/06/1989 False
The current output in the listbox is:
Form1.Name
Form1.Name
Form1.Name

You are writing on listbox the string representation of your Name Class? If yes you just have to override ToString method in your Name class to display what information you want

ListBox's display collections of ListItems, and those have Text and Value properties that control what they display. You could project your collection into an anonymous type before databinding, then set the the DataValueField and DataTextField to your computed properties. It could look something like this:
var DateOrder = names.OrderByDescending(x => x.Date)
.Select(x => new { Text = $"{x.Name} {x.Age} {x.DOB} {x.Male}", Value = x.Name })
.ToList();
lstByDate.DataSource = DateOrder;
lstByDate.DataValueField = "Value";
lstByDate.DataTextField = "Text";

Try ICompare :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication100
{
class Program
{
const string FILENAME = #"c:\temp\test.csv";
static void Main(string[] args)
{
Person person = new Person(FILENAME);
person.Sort();
}
}
public class Person : IComparable
{
public string Name { get;set;}
public int Age { get;set;}
public DateTime DOB { get;set;}
public string sex { get;set;}
List<Person> dataCollection = new List<Person>();
public Person() { }
public Person(string filename)
{
using (var f = new StreamReader(filename))
{
string line = string.Empty;
int rowCount = 0;
while ((line = f.ReadLine()) != null)
{
if (++rowCount > 1)
{
var data = line.Split(',');
dataCollection.Add(new Person() { Name = data[0], Age = Convert.ToInt32(data[1]), DOB = Convert.ToDateTime(data[2]), sex = data[3]});
}
}
}
}
public int CompareTo(object obj)
{
return this.DOB.CompareTo(((Person)obj).DOB);
}
public void Sort()
{
dataCollection.Sort();
}
}
}

Related

Set property value while selecting from list of class objects

Am trying to set value(day value to "Sunday") while selecting from list, like below in method 'getData', is there a way I can set it without really changing class object property 'day' value? I just want it set to 'Sunday' while reading, like 'Sunday' as 'day'.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleAppForChecking
{
public class test
{
public string firstName { get; set; }
public string lastName { get; set; }
public int age { get; set; }
public string day { get; set; }
}
public class TestMain
{
static void Main(string[] args)
{
var tests = new List<test>()
{
new test { firstName = "Mike", lastName = "Toss", age = 20, day = "Monday" },
new test { firstName = "Peter", lastName = "Page", age = 30, day = "Tuesday" },
new test { firstName = "Stacy", lastName = "Page", age = 27, day = "Wednesday" }
};
getData(tests);
GetDate(tests);
}
public static void getData(List<test> _data)
{
var _data1 = _data.Where(w => w.firstName == "Stacy")
.Select(o => new
{
o.firstName,
o.lastName,
day = o.day = "Sunday",
o.age
})
.ToList();
foreach(var d in _data1)
{
Console.WriteLine(d);
}
}
public static void GetDate(List<test> _data1)
{
foreach (var d in _data1)
{
Console.WriteLine(d);
}
}
}
}
_data.Where(w => w.firstName == "Stacy")
.Select(o=> {o.day = "Sunday"; return c;})
.ToList();

Read a XML with Linq C# using where condition

I try to make a little Service for my business but it doesn't works.
<item>
<key>12323</key>
<summary></summary>
<reporter username="12313asdf">1232 asdf iii</reporter>
<cusomfields>
<customfield id="customfield_37723" key="xyz">
<customfieldname>First Name</customfieldname>
<customfieldvalues>
<customfieldvalue>Klaus</customfieldvalue>
</customfieldvalues>
</customfield>
//...many customfields
</customfields>
</item>
I created a c# method with this code -> but it doesn't work :(
XDocument doc = XDocument.Load(fileName);
var obj = (from c in doc.Descendants("item")
select new ServiceRequest_NewUser()
{
TicketID = c.Element("key").Value,
Summary = c.Element("summary").Value,
ReporterNT = c.Element("reporter").Attribute("username").Value,
ReporterFull = c.Element("reporter").Value,
FirstName = (from f in c.Descendants("customfields")
where f.Element("customfield")?.Attribute("id")?.Value == "customfield_37723"
select f.Descendants("customfieldvalues").FirstOrDefault()?.Value).FirstOrDefault()
}).ToList();
foreach (var i in obj)
{
var test = i.FirstName;
Console.WriteLine($"{i.TicketID} {i.Summary} {i.ReporterNT} {i.ReporterFull} {i.FirstName}");
}
Where is my fault? I did a alternative version of code in the comment tag. I need to output the value "Klaus".
I thank you in advance for the help.
If you expected to see Klaus in the FirstName, you should write this:
var obj = (from c in doc.Elements("item")
select new
{
TicketID = c.Element("key")?.Value,
Summary = c.Element("summary")?.Value,
ReporterNT = c.Element("reporter")?.Attribute("username")?.Value,
ReporterFull = c.Element("reporter").Value,
FirstName = (from f in c.Descendants("customfields")
where f.Element("customfield")?.Attribute("id")?.Value == "customfield_37723"
select f.Descendants("customfieldvalues").FirstOrDefault()?.Value).FirstOrDefault()
}).ToList();
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Item> items = doc.Descendants("item").Select(x => new Item()
{
key = (string)x.Element("key"),
summary = (string)x.Element("summary"),
usernameText = (string)x.Element("reporter"),
username = (string)x.Element("reporter").Attribute("username"),
fields = x.Descendants("customfield").Select(y => new Field()
{
id = (string)y.Attribute("id"),
key = (string)y.Attribute("key"),
name = (string)y.Element("customfieldname"),
values = y.Descendants("customfieldvalue").Select(z => (string)z).ToList()
}).ToList()
}).ToList();
List<Item> customfield_37723 = items.Where(x => x.fields.Any(y => y.id == "customfield_37723")).ToList();
foreach (Item item in customfield_37723)
{
Console.WriteLine("Item : key = '{0}', summary = '{1}', username Text = '{2}', username = '{3}'",
item.key, item.summary, item.usernameText, item.username);
foreach (Field field in item.fields)
{
Console.WriteLine(" Field : id = '{0}', key = '{1}', name = '{2}', values = '{3}'",
field.id, field.key, field.name, string.Join(",", field.values));
}
}
Console.ReadLine();
}
}
public class Item
{
public string key { get; set; }
public string summary { get; set; }
public string usernameText { get; set; }
public string username { get; set; }
public List<Field> fields { get; set; }
}
public class Field
{
public string id { get; set; }
public string key { get; set; }
public string name { get; set; }
public List<string> values { get; set; }
}
}

Trouble getting MemberName of "Name" from CustomAttributes = ColumnAttribute of Linq Table Class

I have a little algo I wrote to compare the Linq DataContext table to the sql table. It rolls through the properties of the Linq table and gets the CustomeAttributes of the property, (table columns). It's been working for years, but somebody created a table field with a # sign in it, (UPS#). Linq doesn't like such a name for its properties for obvious reasons. So, it has a member of the ColumnAttribute called "Name" to handle the swap. But, I've always used the "Storage" member for my column name. You would think you would just pick up the "Name" member if it's present, but I can't find it to save my life.
This is the code. Any help is very much appreciated.
public static ColumnInfo[] GetColumnsInfo(Type linqTableClass)
{
// Just looking in the loop to see if I missed something.
foreach (var fld in linqTableClass.GetProperties())
{
foreach (var attr in fld.CustomAttributes)
{
foreach (var arg in attr.NamedArguments)
{
if (arg.MemberName == "Name")
Debug.WriteLine(arg.MemberName);
Debug.WriteLine("{0}", arg.MemberName);
}
}
}
var columnInfoQuery =
from field in linqTableClass.GetProperties()
from attribute in field.CustomAttributes
from namedArgument in attribute.NamedArguments
where namedArgument.MemberName == "DbType"
select new ColumnInfo
{
//ColumnName = field.Name,
ColumnName = namedArgument.MemberName,
DatabaseType = namedArgument.TypedValue.Value.ToString(),
};
return columnInfoQuery.ToArray();
}
and this is the property in the Table Class:
[global::System.Data.Linq.Mapping.ColumnAttribute(Name="PEER_UPS#", Storage="_PEER_UPS_", DbType="Char(31) NOT NULL", CanBeNull=false)]
public string PEER_UPS_
{
get
{
return this._PEER_UPS_;
}
set
{
if ((this._PEER_UPS_ != value))
{
this.OnPEER_UPS_Changing(value);
this.SendPropertyChanging();
this._PEER_UPS_ = value;
this.SendPropertyChanged("PEER_UPS_");
this.OnPEER_UPS_Changed();
}
}
}
I couldn't find a pretty way to get this done. For some reason the ColumnAttribute just didn't want to play nice. Ugly as this is, it works.
public class ColumnInfo
{
public string ColumnName { get; set; }
public string DatabaseType { get; set; }
}
public static IEnumerable<ColumnInfo> GetColumnsInfo(Type linqTableClass)
{
Debug.WriteLine(string.Format("Table: {0}", linqTableClass.Name));
/// In-Case this has to grow in the future. Using a list for the arg names to search for.
/// The primary arg should be in position 0 of the array.
string dbTypeArgName = "DbType";
string fldPrimayName = "Storage";
string fldSecondaryName = "Name";
List<string> fldArgnames = new List<string>() { fldPrimayName, fldSecondaryName };
foreach (var fld in linqTableClass.GetProperties())
{
Debug.WriteLine(string.Format("Field Name: {0}", fld.Name));
foreach (var attr in fld.GetCustomAttributesData().Cast<CustomAttributeData>()
.Where(r => r.AttributeType == typeof(ColumnAttribute))
.Where(a => a.NamedArguments
.Select(n => n.MemberName)
.Intersect(fldArgnames)
.Any()))
{
var fldName = attr.NamedArguments.Where(r => r.MemberName == fldSecondaryName).Count() != 0
? attr.NamedArguments.Where(r => r.MemberName == fldSecondaryName).SingleOrDefault().TypedValue.Value.ToString()
: fld.Name;
var fldType = attr.NamedArguments
.Where(r => r.MemberName == dbTypeArgName)
.Select(r => r.TypedValue.Value.ToString())
.SingleOrDefault();
Debug.WriteLine(string.Format("\tTable Field Name {0} Table Type {1}", fldName, fldType));
yield return new ColumnInfo()
{
ColumnName = fldName,
DatabaseType = fldType,
};
}
}
}
and here is what i suggest:
[sorry, my first example was indeed too simplistic]
Here is how i'd do it:
namespace LinqAttributes
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
public class ColumnInfo
{
public string ColumnName { get; set; }
public string DatabaseType { get; set; }
}
public class Test
{
[System.Data.Linq.Mapping.ColumnAttribute(Name = "Whatever", Storage = "Whatever", DbType = "Char(20)", CanBeNull = true)]
public string MyProperty { get; set; }
[System.Data.Linq.Mapping.ColumnAttribute(Name = "PEER_UPS#", Storage = "_PEER_UPS_", DbType = "Char(31) NOT NULL", CanBeNull = false)]
public string PEER_UPS_ { get; set; }
}
internal class Program
{
public static IEnumerable<ColumnInfo> GetColumnsInfo(Type type)
{
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(type))
{
var columnAttribute = descriptor.Attributes
.OfType<System.Data.Linq.Mapping.ColumnAttribute>().SingleOrDefault();
if (columnAttribute != null)
{
yield return new ColumnInfo
{
ColumnName = columnAttribute.Name,
DatabaseType = columnAttribute.DbType
};
}
}
}
private static void Main(string[] args)
{
foreach (var item in GetColumnsInfo(typeof(Test)))
{
Debug.WriteLine(item.ColumnName);
}
}
}
}
Just tested it.
Cheers!
public class City
{
public City() { }
[Column("id_city")]
public int Id { get; private set; }
}
var obj = new City();
var pro = obj.GetType().GetProperties();
string columnAttribute = pro.GetCustomAttributes<ColumnAttribute>().FirstOrDefault().Name;
if(columnAttribute == "id_city") {
//sucess
}

linq combine model string into single string

Trying to find a simple way to combine strings from several model into a single string using linq to object expressions. Trying to put the result either all in first object where bob's name is, or all in People.names location. Maybe I need to add an another extension method like coalesce?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
People people = new People
{
Persons =
{
new Person{
Name = "Bob",
Age = 15
},
new Person{
Name = "James",
Age = 17
},
new Person{
Name = "Mary",
Age = 15
}
},
};
people.names = people.Persons.Select(p => p.Name).ToList().ToString();
Console.WriteLine(people.names);
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class People
{
public People() {
Persons = new List<Person>();
}
public string names { get; set; }
public IList<Person> Persons { get; set; }
}
}
Could do something like this:
class People
{
public List<Person> Persons { get; set; }
public string Names
{
get
{
if (Persons != null)
{
return String.Join(",", Persons.Select(p => p.Name));
}
else
{
return string.Empty;
}
}
}
}
class Person
{
public string Name { get; set; }
}
You can use string.Join:
Console.WriteLine(String.Join(" ",people.Persons.Select(p => p.Name)));
You can use string.Join to join several strings using a separator. To join the names use a simple select like:
string joinedNames = string.Join(",", people.Persons.Select(p => p.Name));
Dont't forget to add
using System.Linq;
Just for fun versions
people.Aggregate("", (a, b) => $"{a} {b.Name}").Trim()
string.Concat(people.Select(p => p.Name + " ")).Trim()
Crazy version:
string.Concat(people.Zip(
Enumerable.Range(0, people.Count).Select(x => " "),
(p, s) => p.Name + s)).Trim()

Converting objects with string[] properties to CSV or Excel

Is there any library out there that can serialize objects with array properties to .csv?
Let's say I have this model:
public class Product
{
public string ProductName { get; set; }
public int InStock { get; set; }
public double Price { get; set; }
...
public string[] AvailableVariants { get; set; }
}
Would something like that be possible to do?
Edit: I need to present some data in a csv/excel format. The thing is, I'm not sure if there is a simple way of achieving what I want with CSV serialization libraries or if I should rather focus on writing an Excel native file.
An example of result I'm looking for:
Product Name In Stock Price Variants
ABC 241 200 Normal
CAB 300 300 Normal
Red
Blue
CBA 125 100 Normal
White
Awesome
Red
ACB 606 75 Normal
Small
Large
X-Large
What would be the most efficient way to do this?
I'm not aware of any libraries that will do this, here's a console example of how I'd approach writing/reading from a CSV:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace TestingProduct
{
class TestingProduct
{
public class Product
{
public string ProductName { get; set; }
public int InStock { get; set; }
public double Price { get; set; }
public string[] AvailableVariants { get; set; }
public override string ToString() => $"{ProductName},{InStock},{Price}{(AvailableVariants?.Length > 0 ? "," + string.Join(",", AvailableVariants) : "")}";
public static Product Parse(string csvRow)
{
var fields = csvRow.Split(',');
return new Product
{
ProductName = fields[0],
InStock = Convert.ToInt32(fields[1]),
Price= Convert.ToDouble(fields[2]),
AvailableVariants = fields.Skip(3).ToArray()
};
}
}
static void Main()
{
var prod1 = new Product
{
ProductName = "test1",
InStock= 2,
Price = 3,
AvailableVariants = new string[]{ "variant1", "variant2" }
};
var filepath = #"C:\temp\test.csv";
File.WriteAllText(filepath, prod1.ToString());
var parsedRow = File.ReadAllText(filepath);
var parsedProduct = Product.Parse(parsedRow);
Console.WriteLine(parsedProduct);
var noVariants = new Product
{
ProductName = "noVariants",
InStock = 10,
Price = 10
};
var prod3 = new Product
{
ProductName = "test2",
InStock= 5,
Price = 5,
AvailableVariants = new string[] { "variant3", "variant4" }
};
var filepath2 = #"C:\temp\test2.csv";
var productList = new List<Product> { parsedProduct, prod3, noVariants };
File.WriteAllText(filepath2, string.Join("\r\n", productList.Select(x => x.ToString())));
var csvRows = File.ReadAllText(filepath2);
var newProductList = new List<Product>();
foreach (var csvRow in csvRows.Split(new string[] { "\r\n" }, StringSplitOptions.None))
{
newProductList.Add(Product.Parse(csvRow));
}
newProductList.ForEach(Console.WriteLine);
Console.ReadKey();
}
}
}
This code will work with a class that has a single object array property. Do you need something that can handle an object with multiple array properties?
I have written some kind of library to write csv files, have a look:
public static class CsvSerializer
{
public static bool Serialize<T>(string path, IList<T> data, string delimiter = ";")
{
var csvBuilder = new StringBuilder();
var dataType = typeof(T);
var properties = dataType.GetProperties()
.Where(prop => prop.GetCustomAttribute(typeof(CsvSerialize)) == null);
//write header
foreach (var property in properties)
{
csvBuilder.Append(property.Name);
if (property != properties.Last())
{
csvBuilder.Append(delimiter);
}
}
csvBuilder.Append("\n");
//data
foreach (var dataElement in data)
{
foreach (var property in properties)
{
csvBuilder.Append(property.GetValue(dataElement));
if (property != properties.Last())
{
csvBuilder.Append(delimiter);
}
}
csvBuilder.Append("\n");
}
File.WriteAllText(path, csvBuilder.ToString());
return true;
}
}
public class CsvSerialize : Attribute
{
}
Lets pretend you want to serialize following class:
public class MyDataClass
{
[CsvSerialize]
public string Item1 {get; set;}
[CsvSerialize]
public string Item2 {get; set;}
}
Then just do:
public void SerializeData(IList<MyDataClass> data)
{
CsvSerializer.Serialize("C:\\test.csv", data);
}
It takes a IList of your class and writes a csv.
It cant serialize arrays but that would be easy to implement.

Categories

Resources