Is there a LINQ equivalent of string.Join(string, string[]) [duplicate] - c#

This question already exists:
What is the LINQ way to implode/join a string array? [duplicate]
Closed 9 years ago.
Is there any way to convert a collection of objects into a single new object using LINQ?
I want to use this within another LINQ to SQL expression.

Why don't you use the string.Join itself?
string.Join("<br/>", collection.Select(e => e.TextProp));

You can use the Aggregate method...
var myResults = (from myString in MyStrings
select myString)
.Aggregate(string.Empty, (results, nextString)
=> string.Format("{0}<br />{1}", results, nextString));
or
var myResults = MyStrings.Aggregate(string.Empty, (results, nextString)
=> string.Format("{0}<br />{1}", results, nextString));

The normal way would be to use one of the aggregation operators (Aggregate, Sum, Average etc), but it entirely depends on the type and what you want to do. What type are you interested in?
EDIT: Okay, so you want to concatenate strings... I don't think there's anything which will do that in LINQ to SQL itself. Options:
Write a stored proc or TVF to do it in SQL
Fetch the individual strings in LINQ to SQL and concatenate back on the client side

Most of the solutions here are fairly inefficient if you have large numbers of values you want to concatonate. Also, they're not all that readable. If you are going to do this sort of thing frequently, then it's worth building your own extension method to do it. The implementation below allows you to do the equivalent of string.Join(", ", arrayOfStrings) where the arrayOfStrings can be an IEnumerable<T>, and separator can be any object at all. It allows you to do something like this:
var names = new [] { "Fred", "Barney", "Wilma", "Betty" };
var list = names
.Where(n => n.Contains("e"))
.Join(", ");
Two things I like about this are:
It's very readable in a LINQ context.
It's fairly efficient because it uses StringBuilder and avoids evaluating the enumeration twice which is important in a database scenario (L2S, L2E, or L2Nh).
public static string Join<TItem,TSep>(
this IEnumerable<TItem> enuml,
TSep separator)
{
if (null == enuml) return string.Empty;
var sb = new StringBuilder();
using (var enumr = enuml.GetEnumerator())
{
if (null != enumr && enumr.MoveNext())
{
sb.Append(enumr.Current);
while (enumr.MoveNext())
{
sb.Append(separator).Append(enumr.Current);
}
}
}
return sb.ToString();
}

Related

Possible to "flatten" linq output into a period delimited list? [duplicate]

This question already has answers here:
How do I create a comma delimited string from an ArrayList?
(8 answers)
Closed 4 years ago.
I have a key-value pair array that contains an LDAP distinguished name, and I want to retrieve the DNS domain name of the host. (Only the DC's not the fqdn)
Assume that the LDAP parsing is done correctly, and the DC entries when combined constitute the DNS domain name of the host.
Given the code below, is it possible to convert
DC = my
DC = domain
DC = com
into
my.domain.com
I could use a for...each with a stringbuilder but it doesn't feel elegant. Is there a better way?
My code is below:
var kvList = ParseDistinguishedName(ldapName);
StringBuilder sb = new StringBuilder();
var names = (from k in kvList
where k.Key == "DC"
select k.Value);
Very easily, fortunately: string.Join does exactly what you want:
var dotSeparated = string.Join(".", names);
You might want to consider using method calls rather than a query expression for such a simple query, mind you. What you've got is precisely equivalent to:
var names = kvList.Where(k => k.Key == "DC").Select(k => k.Value);
The query expression is fine, but can end up being verbose for simple queries. (Query expressions really shine with let, join etc - anything that introduces transparent identifiers.)
Probably something like this:
kvList.Where(x => x.Key == "DC")
.Select(x => x.Value)
.Aggregate((x,y) => x + "." + y)

Can't get deferred LINQ statements to work in nHibernate

Trying to write dynamic queries using the LINQ provider for NHibernate, but I am having issues. My understanding was that LINQ queries were deferred until called, (i.e. with ToList()), so I have the following code:
string[] filteredIds = new[] { "someIdNotInUse"};
var result = _products
.GetAll()
.Skip(0)
.Take(10);
if (filteredIds != null)
{
result.Where(x => x.Child1.Child2.Any(z => filteredIds.Contains(z.Child3.Id)));
}
var r = result.ToList();
The Where filter in the conditional block is not applied; when I run .ToList, I get records where I expect none. However, if I remove the where filter and append it directly to the _products call, it works as expected. Am I misunderstanding how the LINQ provider works? How is creating a query like this possible, without rewriting the query for every possible filter condition and combination?
Methods in LINQ don't affect the object they're called on - they return a new object representing the result of the call. So you want:
if (filteredIds != null)
{
result = result.Where(...);
}
(Think of it as being a bit like calling Replace or Trim on a string - the string is immutable, so it's only the return value which matters.)

How can I build Linq query with dynamic OR statements?

The following code:
var dynamicQuery = from a in _context.Users select a;
string[] args = new string[] { "aa", "bb", "cc" };
foreach (string word in args)
dynamicQuery = dynamicQuery.Where(x => x.Name.Contains(word));
return dynamicQuery.ToList();
Will allow me to create a Linq query with a dynamic list of AND expressions.
But suppose I wanted to do the same, only with a dynamic list of OR expressions?
You don't need to loop at all:
return _context.Users.Where(x => args.Any(word => x.Name.Contains(word)));
EDIT: More generally, you can use:
Func<User, bool> predicate = user => false;
foreach (var item in items)
{
var predicateCopy = predicate;
predicate = user => predicateCopy(user) || someOtherCondition;
}
return query.Where(predicate);
This will end up with quite deep stacks (with one delegate calling another calling another etc). Where the specific situation allows you to use Any, that would usually be a better approach.
I would expect Any to work in most situations where you've got a collection of items to potentially match against... the non-Any approach is approprate for "in some situations, anyone over 18 is fine... in some situations anyone with a last name beginning with "G" is appropriate, etc.

Linq to create a csv string for some values stored in an array of object using c#

I have an array of object storing some accounts.
12345631
L1234512
P12345
234556
19090912
J123456
Using Linq and .Net 3.5, I want to create a csv string for accounts starting with L or P and is of 6 characters. Following code creates a csv string but how to add the filter?
string[] accounts = accountList.Select(c => c.acctnbr).ToArray();
string csv = string.Join(",", accounts);
The output should be L12345,P12345.
Try this:
string[] accounts = accountList
.Where
(
a=> (a.acctnbr.StartsWith("L") || a.acctnbr.StartsWith("P"))
&&
(a.acctnbr.Length == 6)
)
.Select(c => c.acctnbr)
.ToArray();
string csv = string.Join(",", accounts);
In case you't interested, here's a version using the query syntax instead as well
var accounts = from a in accountList
where (a.acctnbr.StartsWith("L") || a.acctnbr.StartsWith("P"))
&& (a.acctnbr.Length == 6)
select a.acctnbr;
var csv = String.Join("," accounts.ToArray());
Based on the comment you added regarding which solution is better, mine or Cybernate. The solutions are the same, C# let's you write queries in two ways. You can take a look at LINQ Query Syntax versus Method Syntax (C#) for more information.
Relevant bit from ducumentation (though I would strongly urge you to read up more on Linq)
In general, we recommend query syntax because it is usually simpler and more readable; however there is no semantic difference between method syntax and query syntax. In addition, some queries, such as those that retrieve the number of elements that match a specified condition, or that retrieve the element that has the maximum value in a source sequence, can only be expressed as method calls.
string[] accounts = accountList.Select(c => c.acctnbr).ToArray();
IEnumerable<string> namesWithFourCharacters = from name in accounts
where name.StartsWith("L")
select name;
Hope this helps.

How to insert a lambda into a Linq declarative query expression

Let's say you have the following code:
string encoded="9,8,5,4,9";
// Parse the encoded string into a collection of numbers
var nums=from string s in encoded.Split(',')
select int.Parse(s);
That's easy, but what if I want to apply a lambda expression to s in the select, but still keep this as a declarative query expression, in other words:
string encoded="9,8,5,4,9";
// Parse the encoded string into a collection of numbers
var nums=from string s in encoded.Split(',')
select (s => {/* do something more complex with s and return an int */});
This of course does not compile. But, how can I get a lambda in there without switching this to fluent syntax.
Update: Thanks to guidance from StriplingWarrior, I have a convoluted but compilable solution:
var result=from string s in test.Split(',')
select ((Func<int>)
(() => {string u="1"+s+"2"; return int.Parse(u);}))();
The key is in the cast to a Func<string,int> followed by evaluation of the lambda for each iteration of the select with (s). Can anyone come up with anything simpler (i.e., without the cast to Func followed by its evaluation or perhaps something less verbose that achieves the same end result while maintaining the query expression syntax)?
Note: The lambda content above is trivial and exemplary in nature. Please don't change it.
Update 2: Yes, it's me, crazy Mike, back with an alternate (prettier?) solution to this:
public static class Lambda
{
public static U Wrap<U>(Func<U> f)
{
return f();
}
}
...
// Then in some function, in some class, in a galaxy far far away:
// Look what we can do with no casts
var res=from string s in test.Split(',')
select Lambda.Wrap(() => {string u="1"+s+"2"; return int.Parse(u);});
I think this solves the problem without the ugly cast and parenarrhea. Is something like the Lambda.Wrap generic method already present somewhere in the .NET 4.0 Framework, so that I do not have to reinvent the wheel? Not to overburden this discussion, I have moved this point into its own question: Does this "Wrap" generic method exist in .NET 4.0.
Assuming you're using LINQ to Objects, you could just use a helper method:
select DoSomethingComplex(s)
If you don't like methods, you could use a Func:
Func<string, string> f = s => { Console.WriteLine(s); return s; };
var q = from string s in new[]{"1","2"}
select f(s);
Or if you're completely hell-bent on putting it inline, you could do something like this:
from string s in new[]{"1","2"}
select ((Func<string>)(() => { Console.WriteLine(s); return s; }))()
You could simply do:
var nums = from string s in encoded.Split(',')
select (s => { DoSomething(); return aValueBasedOnS; });
The return tells the compiler the type of the resulting collection.
How about this:
var nums= (from string s in encoded.Split(',') select s).Select( W => ...);
Can anyone come up with anything
simpler?
Yes. First, you could rewrite it like this
var result = from s in encoded.Split(',')
select ((Func<int>)(() => int.Parse("1" + s + "2")))();
However, that's not really readable, particularly for a query expression. For this particular query and projection, the let keyword could be used.
var result = from s in encoded.Split(',')
let t = "1" + s + "2"
select int.Parse(t);
IEnumerable integers = encoded.Split(',').Select(s => int.Parse(s));
Edit:
IEnumerable<int> integers = from s in encoded.Split(',') select int.Parse(string.Format("1{0}2",s));

Categories