Concatenating objects with linq - linq

I have a class like this
public class test{
public string a { get; set; }
public string b { get; set; }
}
and a list of objects
List<test> list= new List<test>();
list.Add(new test() {a = "1a", b = "1b" });
list.Add(new test() {a = "2a", b = "2b" });
...
i want concatenate the elements and have a string like
"1a 1b + 2a 2b" ... etc
Can i use Linq to do this?

This can be done in Linq by mapping to a string as follows.
string Result =
String.Join(" + ",
list.Select(iObj => String.Format("{0} {1}", iObj.a, iObj.b)));

String.Join(" + ", list.Select(x => /*What you want*/));
will do the trick!

Related

LINQ sorting on sub table converted to CSV

I have an EF model (note joined partial classes togther for clarity)
public class Product
{
public System.Guid ProductID { get; set; }
public string Product{ get; set; }
public virtual ICollection<Module> Modules { get; set; }
[NotMapped]
public string ModulesCSV
{
get
{
string retList = "";
foreach (Module aModule in Modules)
{
if (retList.Length > 0)
retList += ", ";
retList += aModule.Module.Trim ();
}
return retList;
}
}
}
now I need to sort on the CSV as well as the other columns, I realise that link to sql has problems wth this. My normal sort cannot do this I was wondering if anyone knows a good way of doing it va LINQ and could please share it?
The current sort line is where 'sort' is the column name and 'sortdir' is "ASC" or "DESC" which works a treat for the other columns.
query = db.Products.AsExpandable().Where(predicate).OrderBy(sort + " " + sortdir);
Not pretty or as efficient but
if (sort != "CSV") // as non ddb column has to be sorted on list
query = db.Products.AsExpandable().Where(predicate).OrderBy(sort + " " + sortdir);
else
{
query = db.Products.AsExpandable().Where(predicate);
if (sortdir=="ASC")
{
query = db.Products.AsExpandable().Where(predicate).ToList<Product>().AsQueryable <Product> ();
query = query.OrderBy(r => r.GetType().GetProperty(sort).GetValue(r, null));
}
else
{
query = db.Products.AsExpandable().Where(predicate).ToList<Product>().AsQueryable <Product> ();
query = query.OrderByDescending(r => r.GetType().GetProperty(sort).GetValue(r, null));
}
}

ProtoBuf-Linq error message “ Invalid field in source data: 0”

I've encountered the following issue while using protobuf-linq:
using (var stream = new MemoryStream())
{
SerializeMultiple(PrepareData(), stream);
}
private static void SerializeMultiple(IEnumerable<Person> persons, Stream stream)
{
foreach (var person in persons)
{
Serializer.Serialize(stream, person);
}
stream.Position = 0;
var q = RuntimeTypeModel.Default.AsQueryable<Person>(stream,null);
var results = from e in q
where e.Id % 2 == 0
select new { e.Id, e.Name };
Console.WriteLine("first : " + results.First().Id);
Console.ReadLine();
}
static IEnumerable<Person> PrepareData()
{
for (int i = 0; i < (int) 1e+04; i++)
{
yield return new Person {Id = i, Name= "John" + i, Address = "Address" + i*i};
}
}
[ProtoContract]
class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public string Address { get; set; }
}
The AsQueryable line throws the aforementioned exception:
Invalid field in source data: 0
Any thoughts on this matter?
It's not protobuf-linq error. When serializing items into a stream, you should use SerializeWithLengthPrefix to prefix every message with its length, to allow separate them. By default, protobuf-linq uses PrefixStyle.Base128. Below you can find a snippet making it right:
Serializer.SerializeWithLengthPrefix(stream, person, PrefixStyle.Base128);

How do I combine columns together

I have 2 lists that contain different data but have similar columns.
Basically I want to join these lists but then merge the similar columns into 1.
var listCombo= List1.Where(a=>DataIds.Contains(a.dataId)).DefaultIfEmpty()
.Join(List2,
list1 => list1.key,
list2 => list2.key,
(L1,L2) => new
{
L2.key,
L2.dataId,
L2.dataValue,
L2.date,
L1.secId,
L1.dataId,
L1.dataValue
});
I'd like to combine the dataId and dataValue columns together. How do I do that?
So I can just say listCombo.dataId or listCombo.dataValue rather than having to uniquely name them.
If I understand your question, you're trying to combine the two fields into one. Assuming that you have a Class
public class List1 {
public int dataId {get;set;}
public string dataValue {get;set;}
public string combinedValue {get;set;}
}
No you can use like,
var listCombo= List1.Where(a=>DataIds.Contains(a.dataId)).DefaultIfEmpty()
.Join(List2,
list1 => list1.key,
list2 => list2.key,
(L1,L2) => new List1
{
dataId = L2.dataId,
dataValue = L2.dataValue
combinedValue = L2.dataId + " - " L2.dataValue
});
I would use POCO methods for a list1, list2, and a third list which is a combo of both. I would be sure that if you are combining unlike types you do appropriate casts or if you want complex types you can define them as their own properties or what not.
static void Main(string[] args)
{
List<A> lisA = new List<A> {new A {AId = 1, AName = "Brett"}, new A {AId = 2, AName = "John"}};
List<B> lisB = new List<B> {new B { BId = 1, BName = "Doe" }, new B { BId = 2, BName = "Howard" } };
List<C> lisC = lisA.Join(lisB,
list1 => list1.AId,
list2 => list2.BId,
(L1, L2) => new C
{
CId = L1.AId,
CName = L1.AName + " " + L2.BName
}).ToList();
lisC.ForEach(
n => Console.WriteLine(n.CName + "\n")
);
}
public class A
{
public int AId { get; set; }
public string AName { get; set; }
}
public class B
{
public int BId { get; set; }
public string BName { get; set; }
}
public class C
{
public int CId { get; set; }
public string CName { get; set; }
}

How To: Joining three lists using Linq to objects

Problem is with the addresses not being outputted
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LinqToObjects
{
class Program
{
static void Main(string[] args)
{
var customers = Customer.GetAllCustomers();
var addresses = Address.GetAllAddresses();
var addressRelations = AddressRelation.GetAllAddressRelations();
var results = customers
.Join(addressRelations,
c => c.CustomerID,
ar => ar.CustomerID,
(c, ar) => new
{
CustomerName = c.FirstName + " " + c.LastName,
CustomerID = c.CustomerID,
AddressRelID = ar.AddressID
});
var resultsJoined = results
.GroupJoin(addresses,
ar => ar.AddressRelID,
a => a.AddressID,
(ar, a) => new
{
CustomerName = ar.CustomerName,
AddressLine = addresses.Select(b => b.StreetAddress).FirstOrDefault()
});
foreach(var item in resultsJoined)
{
Console.WriteLine(item.CustomerName);
Console.WriteLine(item.AddressLine);
Console.WriteLine("-----------------");
}
}
}
public class AddressRelation
{
public int AddressRelationID { get; set; }
public int CustomerID { get; set; }
public int AddressID { get; set; }
public AddressRelation(int id, int customerId, int addressId)
{
AddressRelationID = id; CustomerID = customerId; AddressID = addressId;
}
public static List<AddressRelation> GetAllAddressRelations()
{
var AllAddressRelations = new List<AddressRelation>();//simulate data returned from db
var addressRelation1 = new AddressRelation(1, 1, 1);
var addressRelation2 = new AddressRelation(2, 3, 3);
var addressRelation3 = new AddressRelation(3, 2, 2);
AllAddressRelations.Add(addressRelation1);
AllAddressRelations.Add(addressRelation2);
AllAddressRelations.Add(addressRelation3);
return AllAddressRelations;
}
}
public class Address
{
public int AddressID { get; set; }
public string StreetAddress { get; set; }
public Address(int id, string streetAddress)
{
AddressID = id; StreetAddress = streetAddress;
}
public static List<Address> GetAllAddresses()
{
var AllAddresses = new List<Address>();
Address customer1Address = new Address(1, "Elm St");
Address customer2Address = new Address(2, "Willow Way");
Address customer3Address = new Address(3, "Linq Ln");
AllAddresses.Add(customer1Address);
AllAddresses.Add(customer2Address);
AllAddresses.Add(customer3Address);
return AllAddresses;
}
}
public class Customer
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Customer(int id,string firstName, string lastName)
{
CustomerID = id; FirstName = firstName; LastName = lastName;
}
public static List<Customer> GetAllCustomers()
{
var AllCustomers = new List<Customer>();
var customer1 = new Customer(1, "James", "T");
var customer2 = new Customer(2, "Donnie", "H");
var customer3 = new Customer(3, "Sarah", "H");
AllCustomers.Add(customer1);
AllCustomers.Add(customer2);
AllCustomers.Add(customer3);
return AllCustomers;
}
}
}
The query isn't very expressive. If I was going to join three lists using LinqToObjects, I'd do this:
var query =
from c in customers
join xr in addressRelations on c.CustomerId equals xr.CustomerId
join a in addresses on xr.AddressId equals a.AddressId
select new {Customer = c, Address = a};
Looks like another mistake. I bet that AddressRelId is the key to the AddressRelation table, and not what you want use to connect to the Address table.
.GroupJoin(addresses,
ar => ar.Address**Rel**ID,
a => a.AddressID,
In response to comment:
var query = customers
.Join(addressRelations,
c => c.CustomerId,
xr => xr.CustomerId,
(c, xr) => new {c, xr})
.Join(addresses,
x => x.xr.AddressId,
a => a.AddressId,
(x, a) => new {c = x.c, xr = x.xr, a = a})
.Select(x => new {Customer = x.c, Address = x.a});
It's returning the first customer address because you've told it to:
AddressLine = addresses.Select(b => b.AddressLine1).FirstOrDefault()
Here, addresses is all addresses. I suspect you just want:
AddressLine = a.Select(b => b.AddressLine1).FirstOrDefault()

Linq Unique Values

i have a list of generic class which consists of 2 string property and 1 List as a property
code snipnets is as follows:
public Class abc
{
public int ID { get; set; }
public String Name { get; set; }
List<String> myList;
public List<String> Subjects
{
get
{
if (myList == null)
{
myList = new List<string>();
}
return myList;
}
}
public abc()
{
}
public abc(int id, String name, params string[] subjects)
{
Subjects.AddRange(subjects.AsEnumerable<String>());
ID = id;
Name = name;
}
}
List<abc> myList = new List<abc>();
myList.Add(new abc(1, "p1", "Maths", "Science"));
myList.Add(new abc(2, "p2", "Maths", "Art"));
myList.Add(new abc(3, "p3", "Art", "Science"));
myList.Add(new abc(4, "p4", "Geometry", "Maths"));
I need the output as
Subject Count Person
Maths 3 p1,p2,p4
Science 2 p1,p3
Art 2 p2,p3
Geometry 1 p4
Looks like you want something like:
var query = from item in myList
from subject in item.Subjects
group item.Name by subject into g
select new { Subject = g.Key,
Count = g.Count(),
Person = string.Join(",", g) };
(Change g into g.ToArray() in the string.Join call if you're using .NET 3.5.)
var result =myList.SelectMany(p => p.Subjects
.Select(q => new{Person = p.Name, Subject = q, ID = p.ID}))
.GroupBy(p => p.Subject)
.Select(p => new {Name = p.Key, Count = p.Count(), Persons = p
.Aggregate("", (a, b) => a + b.Person
+ ",").TrimEnd(',')}).OrderBy( p => p.Count);
Iterate over this collection, and print result as needed - properties of a result are Name, Count, Persons

Resources