How to intertwine two strings or arrays, possibly with String.Join() - c#

I have the following string arrays:
var myArray1 = new string[] {"A", "B", "C"};
var myArray2 = new string[] {"t1", "t2"};
I would like to be able to produce a final string that looks like this:
var myFinalString = "t1.A, t2.A, t1.B, t2.B, t1.C, t2.C";
I know I can iterate through each element of the array and build the string manually. However, I'd like to know if there's a better way. I tried to figure out how to make String.Join() method work, but couldn't :-(.

I don't know that any direct method exists, but this one-liner
return
from a in myArray
from b in tTerms
select string.Format("{0}.{1}", b, a)
should do it.

This works:
var query = from x in new[]{"A", "B", "C"}
from y in new[]{"t1", "t2"}
select y + "." + x;
var result = string.Join(", ", query.ToArray());

The term for such sequence is "Cartesian Product".
Here is long blog by Eric Lippert on it Computing a Cartesian Product with LINQ
As it is already shown in other answers sequence of tuples can be obtained with following code and than aggregated (using Join in case of string, or Aggregate for other type of result) to produce your final string:
var product =
from first in s1
from second in s2
select new[] { first, second };
var result String.Join(", ",
product.Select(p => String.Format("{0}.{1}", p.first, p.second));

If the two sequences are of the same length, you could probably put Enumerable.Zip to work for you.
var myFinalString = myArray.Zip(mySecondArray, (f, s) => f + "." + s);

Related

How to concatenate two List<string> to a single string using Aggregate method

I have two lists of strings. My manager's requirement is to concatenate both lists and output as a string using LINQ.
List<string> upper = new List<string> { "A", "B", "C" };
List<string> lower = new List<string> { "a", "b", "c" };
The output should be something as below:
//string output = "A:a,B:b,C:c"
And to achieve this, I need to use LINQ Aggregate method or other extension methods available. Please help
You are looking for the method Zip and maybe combined with string.Join
Console.WriteLine(string.Join(",", upper.Zip(lower, (u, l) => u + ":" + l)));
This outputs: A:a,B:b,C:c
You need Zip method not Aggregate:
If you want the result as a List of String:
List<string> result = upper.Zip(lower, (first, second) => first + ":" + second).ToList();
If you want the result as a string you can either use String.Join method like this:
string output = string.Join(",", result);
Or Aggregate method as you are looking for like this:
string output = result.Aggregate((f, s) => f + "," + s);
Use Enumerable.Zip:
var results = upper.Zip(lower, (up, low) => $"{up}:{low}");
Now to convert it into a single string:
string output = string.Join(",", results);

Pair values from two lists

I have two lists with me as per the following example.
List<string> words = new List<string>() {"V","H","M" };
List<int> numbers = new List<int>() {10,20,30 };
I need to pair the values of these two lists so that my output needs to be exactly like the following text.
Desired output : V10 H20 M30
You could use Zip method for that.
You can try the following:
String.Join(" ", words.Zip(numbers, (first, second) => first + second))
Try using Zip:
var result = words
.Zip(numbers, (w, n) => $"{w}{n}");
Console.Write(string.Join(" ", result));
I'm a bit late to the party but here's a very simple way of doing it without Zip: (x = item, y = index)
var mergedList = words.Select((x, y) => $"{x}{numbers.ElementAt(y)}");

Order of groups with dynamic linq

Somewhat similar to this question:
Where do I put the "orderby group.key" in this LINQ statement?
Except I'm using Dynamic.Linq which makes this a bit harder. I have a bunch of data coming from a database and then I'm grouping by some field and then outputing the result. The problem is that the ordering of the groups seems to randomly jump around which isn't very convenient for the end-user. So taking inspiration from the linked question, if I had this:
string[] words = { "boy","car", "apple", "bill", "crow", "brown" };
// note the first non-dynamic select here was just because I don't think dynamic linq
// will support indexing a string like that and it's not an important detail anyway
var wordList = words.Select(w => new {FirstLetter = w[0], Word = w})
.GroupBy("new (FirstLetter)","Word");
foreach(IGrouping<object, dynamic> g in wordList)
{
Console.WriteLine("Words that being with {0}:",
g.Key.ToString().ToUpper());
foreach (var word in g)
Console.WriteLine(" " + word);
}
Console.ReadLine();
How would I get it to order the keys? At least part of the problem is that the dynamic GroupBy returns an IEnumerable. I thought it might be as easy as:
var wordList = words.Select(w => new {FirstLetter = w[0], Word = w})
.GroupBy("new (FirstLetter)","Word")
.OrderBy("Key");
But that gives me a System.ArgumentException (At least one object must implement IComparable.) when it hits the foreach loop.
My actual code in my project is a little more complicated and looks something like this:
var colGroup = row.GroupBy(string.Format("new({0})",
string.Join(",", c)), string.Format("new({0})",
string.Join(",", v)));
Where c is a list of strings that I need to group by and v is a list of strings that I need to select in each group.
Ok - this is one way to do it, but it might be a little to static to be useful. The problem is that I had this part:
.GroupBy("new (FirstLetter)","Word");
Using new because I can't use a value type as a key (I had another question about that: https://stackoverflow.com/a/26022002/1250301). When with the OrderBy("Key") part, the problem is that it doesn't have a way to compare those dynamic types. I could solve it like this:
var wordList = words.Select(w => new {FirstLetter = w[0].ToString(), Word = w})
.GroupBy("FirstLetter","Word")
.OrderBy("Key");
Making the key a string. Or like this:
var wordList = words.Select(w => new {FirstLetter = w[0], Word = w})
.GroupBy("new (FirstLetter as k)","Word")
.OrderBy("Key.k");
Making it order by something (a char) that is comparable.
I can make it work with my actual problem like this (but it's kind of ugly):
var colGroup = row.GroupBy(string.Format("new({0})", string.Join(",", c)),
string.Format("new({0})", string.Join(",", v)))
.OrderBy(string.Join(",", c.Select(ob => string.Format("Key.{0}", ob))));
I am not sure what you are trying to do, but is that syntax even compiling?
try:
string[] words = { "boy","car", "apple", "bill", "crow", "brown" };
var wordList = words.Select(w => new {FirstLetter = w[0], Word = w})
.GroupBy(x => x.FirstLetter, x => x.Word)
.OrderBy(x => x.Key);

Compare value to array of strings using StartsWith

I have an array:
string[] exceptions = new string[] { "one", two", "one_1", "three" };
.. I want to be able to say:
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
So I want myCollection to be filtered to only show those records whose Property[3].Value does not StartWith a value in the exceptions array. I know StartsWith doesn't take a collection so I'm unsure if this is possible via LINQ or not.
Is this possible in LINQ?! Or am I trying to shoehorn my problem into a LINQ solution?
EDIT: I should say, Contains is not an option since I only want to exclude elements whose property startswith the exception string.
var result = myCollection.Where(c =>
exceptions.All(e =>
!c.Property[3].Value.StartsWith(e));
Try this:
string[] exceptions = new string[] { "one", "two", "one_1", "three" };
var result = from c in myCollection
where !exceptions.Any(exception =>
c.Property[3].Value.StartsWith(exception))
select c;
You could use IndexOfAny (and check result is index position zero) as that takes a collection.
You can select the collection of item you don't want then do a IEnumerable.Except().
I should look like this :
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
var finalResult = myCollection.Except(myCollection.Select(i => i.StartWith(exception)));
var result = myCollection
.where(
rs=>exceptions
.where(
rs1=>!rs.property[3].value.startsWith(rs1)
)
)

string.Join throws OutOfMemory Exception

I have a list of strings and I want to join them with " "(space) between them, so I use the string.Join method:
foreach (var line in lines)
{
var strings = lines.Where(l => l.Code == line.Code).Select(l => l.Data);
var original = string.Join(" ", strings);
}
Data looks something like this: "123456789, 987654321, 32132, 7873892 ..."
But I get an OutOfMemoryException. Why? each string is approximatly 100-150 characters and there are 5-10 strings in the list.
Is there a better way then the string.Join?
Try this (and let us know if you get the same error):
lines.GroupBy(l => l.Code).Select(l => string.Join(" ", l.Select (x => x.Data)));
foreach (var line in lines.GroupBy(p=>p.Code))
{
var original = string.Join(" ", line.Select(p=>p.Data));
}
The StringBuild() class can join strings and isn't immutable.
Here's an MSDN article talking about immutable string vs how StringBuilder works.
http://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.71).aspx

Categories