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()
Related
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();
Is there any chance to use graphLookup aggregate stage with POCO classes and not bson documents?
All examples I've found are using BsonDocuments and it makes me really confused.
Thanks.
let's take the example scenario of wanting to get back a breadcrumb result for a given category in a library...
here's a full program that inserts some seed data and uses a graphlookup aggregation stage to get the breadcrumb for the Mindfulness category:
note: i've used MongoDB.Entities library for brevity. the aggregate query would be the same for the official driver.
using MongoDB.Driver;
using MongoDB.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TestApplication
{
public class Category : Entity
{
public string Name { get; set; }
public string ParentCategory { get; set; }
}
public class Result
{
public string[] BreadCrumb { get; set; }
}
public static class Program
{
private static async Task Main()
{
await DB.InitAsync("test");
await new[] {
new Category { Name = "Books" },
new Category { Name = "Sci-Fi", ParentCategory = "Books" },
new Category { Name = "Space", ParentCategory = "Sci-Fi" },
new Category { Name = "AI", ParentCategory = "Sci-Fi" },
new Category { Name = "Self-Help", ParentCategory = "Books" },
new Category { Name = "Mindfulness", ParentCategory = "Self-Help" },
new Category { Name = "Hypnotherapy", ParentCategory = "Self-Help" }
}.SaveAsync();
var collection = DB.Collection<Category>();
var result = await collection.Aggregate()
.Match(c => c.Name == "Mindfulness")
.GraphLookup<Category, string, string, string, Category, IEnumerable<Category>, object>(
from: collection,
connectFromField: nameof(Category.ParentCategory),
connectToField: nameof(Category.Name),
startWith: $"${nameof(Category.Name)}",
#as: "BreadCrumb",
depthField: "order")
.Unwind("BreadCrumb")
.SortByDescending(x => x["BreadCrumb.order"])
.Group("{_id:null, BreadCrumb:{$push:'$BreadCrumb'}}")
.Project("{_id:0, BreadCrumb:'$BreadCrumb.Name'}")
.As<Result>()
.ToListAsync();
var output = string.Join(" > ", result[0].BreadCrumb);
Console.WriteLine(output); //Books > Self-Help > Mindfulness
Console.ReadLine();
}
}
}
This question already has answers here:
DISTINCT() and ORDERBY issue
(4 answers)
Closed 2 years ago.
I am selecting from a table using LINQ.
I want to order by the sum of two columns.
Here is a simplified version of what isn't working for me
List<DTO.Test> rtn = (from i in db.Table1
orderby i.col1 + i.col2 descending
select i).Take(200).ToList();
****** Edit - this is the full code
List<DTO.Investigation> rtn = (from i in db.Investigations
where i.IsDeleted == false
orderby i.total + i.prevtotal descending
select new DTO.Investigation()
{
InvestigationID = i.InvestigationID,
InvestigationDate = i.InvestigationDate.Value,
}).Distinct().Take(200).ToList();
Your original question had orderby col1 + col2 descending, but the correct syntax for orderby is:
orderby i.col1 + i.col2 descending
Make sure you have using System.Linq near the top of the file.
A fully working solution:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static ApplicationDbContext db = new ApplicationDbContext();
static void Main(string[] args)
{
if (!db.People.Any())
{
db.People.Add(new Person { Name = "John", Score1 = 5, Score2 = 1 });
db.People.Add(new Person { Name = "Mary", Score1 = 2, Score2 = 5 });
db.SaveChanges();
}
// Query Syntax
List<PersonDto> results = (from p in db.People
orderby p.Score1 + p.Score2 descending
select new PersonDto { Id = p.Id, Name = p.Name, TotalScore = p.Score1 + p.Score2 })
.Take(200)
.ToList();
// Method Syntax
List<PersonDto> results2 = db.People
.OrderByDescending(p => p.Score1 + p.Score2)
.Select(p => new PersonDto { Id = p.Id, Name = p.Name, TotalScore = p.Score1 + p.Score2 })
.Take(200)
.ToList();
Console.WriteLine("{0,-5}{1,-10}{2,-10}", "Id", "Name", "TotalScore");
foreach (var item in results1)
{
Console.WriteLine("{0,-5}{1,-10}{2,-10}", item.Id, item.Name, item.TotalScore);
}
Console.ReadKey();
}
}
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext() : base(#"Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=Db63409328; Integrated Security=true")
{
}
public DbSet<Person> People { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Score1 { get; set; }
public int Score2 { get; set; }
}
public class PersonDto
{
public int Id { get; set; }
public string Name { get; set; }
public int TotalScore { get; set; }
}
}
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();
}
}
}
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)