Set property value while selecting from list of class objects - c#

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();

Related

c# cross join two same type of lists

So here I have some code, which works ok. But I want to change the select part to something else, I am not sure what other methods I can use any help would be appreciated.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var all = new List<People>{new People{Id = 1, Name = "andy1", Age = null}, new People{Id = 2, Name = "andy2", Age = null}, new People{Id = 3, Name = "andy3", Age = null}, new People{Id = 4, Name = "andy4", Age = null}, };
var someOfThem = new List<People>{new People{Id = 1, Name = null, Age = 1}, new People{Id = 2, Name = null, Age = 1},new People{Id = 3, Name = null, Age = 1}};
var test = someOfThem.Select(c =>
{
c.Name = all.Find(a => a.Id == c.Id).Name;
return c;
});
foreach (var item in test)
Console.WriteLine("{0}={1}={2}", item.Id, item.Name, item.Age);
}
}
public class People
{
public int Id
{
get;
set;
}
public int? Age
{
get;
set;
}
public string Name
{
get;
set;
}
}
And here is the result.
1=andy1=1
2=andy2=1
3=andy3=1
I am just wondering is there another way to achieve the same result but a more elegant way? or an easier way?
var test = someOfThem.Select(c =>
{
c.Name = all.Find(a => a.Id == c.Id).Name;
return c;
});
Update
Sorry I did not show my problem properly at first, I have updated my quesiton. Please have a look again.
You can use C#'s LINQ keywords and more specifically, the join keyword assosciated with it:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var all = new List<People> { new People { Id = 1, Name = "andy1", }, new People { Id = 2, Name = "andy2", }, new People { Id = 3, Name = "andy3", }, new People { Id = 4, Name = "andy4", }, };
var someOfThem = new List<People> { new People { Id = 1, Name = null, }, new People { Id = 2, Name = null, } };
var test = from item in someOfThem
join element in all on item.Id equals element.Id
select element;
foreach (var item in test)
Console.WriteLine("{0}={1}", item.Id, item.Name);
}
}
public class People
{
public int Id
{
get;
set;
}
public string Name
{
get;
set;
}
}
The code version would be
var test = someOfThem.Join(all, item => item.Id, element => element.Id, (item, element) => element);
as shown in Robert's comment
You can use the Join (you can also use a dictionary, but I'm not going to show it):
Here's the syntax for join:
var test = someOfThem.Join(all, item => item.Id, element => element.Id,
(item, element) => new Person {
Id = item.Id ?? element.Id,
Name = item.Name ?? element.Name,
Age = item.Age ?? element.Age
});
You can implement Equals and GetHashCode in your People class and use Intersect.
Or, create an EqualityComparer, that way your comparison logic is decoupled:
class Program
{
public static void Main()
{
var all = new List<People> { new People { Id = 1, Name = "andy1", }, new People { Id = 2, Name = "andy2", }, new People { Id = 3, Name = "andy3", }, new People { Id = 4, Name = "andy4", }, };
var someOfThem = new List<People> { new People { Id = 1, Name = null, }, new People { Id = 2, Name = null, } };
var test = all.Intersect(someOfThem, new PeopleIdComparer()).ToList();
foreach (var item in test)
Console.WriteLine("{0}={1}", item.Id, item.Name);
}
}
public class PeopleIdComparer : IEqualityComparer<People>
{
public bool Equals(People x, People y)
{
return x.Id == y.Id;
}
public int GetHashCode(People obj)
{
return HashCode.Combine(obj.Id);
}
}
public class People
{
public int Id
{
get;
set;
}
public string Name
{
get;
set;
}
}

Output an ordered collection (using LINQ) into a listbox

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();
}
}
}

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()

How to access a property of a class by its name?

I find it hard to clearly describe the case in a one-sentence title. Here is the example:
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public enum PersonProperties
{
FirstName = 1,
MiddleName = 2,
LastName = 3
}
I am hoping to do this:
foreach (var p in Persons) {
var nameCollection=new List<string>();
foreach (var s in (SectionsEnum[]) Enum.GetValues(typeof (SectionsEnum)))
{
nameCollection.Add(p.GetPropertyByName(s);
}
}
Now, how can we implement the GetPropertyByName() part?
You could do this directly using reflection:
public string GetPropertyByName(SectionsEnum s)
{
var property = typeof(Person).GetProperty(s.ToString());
return (string)property.GetValue(this);
}
Or maybe with a switch.
public string GetPropertyByName(SectionsEnum s)
{
switch (s)
{
case SectionsEnum.FirstName:
return this.FirstName;
case SectionsEnum.MiddleName:
return this.MiddleName;
case SectionsEnum.LastName:
return this.LastName;
default:
throw new Exception();
}
}
But I'd ask if you wouldn't be better served by a wholly different approach, e.g. a list:
public IList<string> NameProperties
{
get
{
return new[] { FirstName, MiddleName, LastName };
}
}
Or instead of having SectionsEnum, use Funcs:
//was
SectionsEnum s = SectionsEnum.FirstName;
//instead
Func<Person, string> nameFunc = p => p.FirstName;
string name = nameFunc(myPerson);
this should be a good starting point for you
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Person p = new Person() { FirstName ="a", MiddleName = "b", LastName = "c" };
List<string> result = new List<string>();
string[] enums = Enum.GetNames(typeof(PersonProperties));
foreach(string e in enums)
{
result.Add(p.GetType().GetProperty(e).GetValue(p, null).ToString());
}
int i = 0;
foreach (string e in enums)
{
Console.WriteLine(string.Format("{0} : {1}", e, result[i++]));
}
Console.ReadKey(false);
}
}
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public enum PersonProperties
{
FirstName = 1,
MiddleName = 2,
LastName = 3
}
}

Uppercase a List of object with LINQ

I have the code below. I'd like to convert all items in this list to uppercase.
Is there a way to do this in Linq ?
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class MyClass
{
List<Person> myList = new List<Person>{
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
}
Update
I don't want to loop or go field by field. Is there a way by reflection to uppercase the value for each property?
Why would you like to use LINQ?
Use List<T>.ForEach:
myList.ForEach(z =>
{
z.FirstName = z.FirstName.ToUpper();
z.LastName = z.LastName.ToUpper();
});
EDIT: no idea why you want to do this by reflection (I wouldn't do this personally...), but here's some code that'll uppercase all properties that return a string. Do note that it's far from being perfect, but it's a base for you in case you really want to use reflection...:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public static class MyHelper
{
public static void UppercaseClassFields<T>(T theInstance)
{
if (theInstance == null)
{
throw new ArgumentNullException();
}
foreach (var property in theInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var theValue = property.GetValue(theInstance, null);
if (theValue is string)
{
property.SetValue(theInstance, ((string)theValue).ToUpper(), null);
}
}
}
public static void UppercaseClassFields<T>(IEnumerable<T> theInstance)
{
if (theInstance == null)
{
throw new ArgumentNullException();
}
foreach (var theItem in theInstance)
{
UppercaseClassFields(theItem);
}
}
}
public class Program
{
private static void Main(string[] args)
{
List<Person> myList = new List<Person>{
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
MyHelper.UppercaseClassFields<Person>(myList);
Console.ReadLine();
}
}
LINQ does not provide any facilities to update underlying data. Using LINQ, you can create a new list from an existing one:
// I would say this is overkill since creates a new object instances and
// does ToList()
var updatedItems = myList.Select(p => new Person
{
FirstName = p.FirstName.ToUpper(),
LastName = p.LastName.ToUpper(),
Age = p.Age
})
.ToList();
If using LINQ is not principal, I would suggest using a foreach loop.
UPDATE:
Why you need such solution? Only one way of doing this in generic manner - reflection.
the Easiest approach will be to use ConvertAll:
myList = myList.ConvertAll(d => d.ToUpper());
Not too much different than ForEach loops the original list whereas ConvertAll creates a new one which you need to reassign.
var people = new List<Person> {
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
people = people.ConvertAll(m => new Person
{
FirstName = m.FirstName?.ToUpper(),
LastName = m.LastName?.ToUpper(),
Age = m.Age
});
to answer your update
I don't want to loop or go field by field. Is there a way by
reflection to uppercase the value for each property?
if you don't want to loop or go field by field.
you could use property on the class to give you the Uppercase like so
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string FirstNameUpperCase => FirstName.ToUpper();
public string LastNameUpperCase => LastName.ToUpper();
}
or you could use back field like so
public class Person
{
private string _firstName;
public string FirstName {
get => _firstName.ToUpper();
set => _firstName = value;
}
private string _lastName;
public string LastName {
get => _lastName.ToUpper();
set => _lastName = value;
}
public int Age { get; set; }
}
You can only really use linq to provide a list of new objects
var upperList = myList.Select(p=> new Person {
FirstName = (p.FirstName == null) ? null : p.FirstName.ToUpper(),
LastName = (p.LastName == null) ? null : p.LastName.ToUpper(),
Age = p.Age
}).ToList();
p.lastname.ToString().ToUpper().Contains(TextString)

Categories

Resources