Better ways to convert tuple list to string - c#

I have a List in below structure:
Tuple<string, string>
like this:
And I would like to join the list to form a string like below:
['A', '1'],['B', '2'], ['C', '3']...
And I am now using below code to do:
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += "[ '" + list[i].Item1 + "', '" + list[i].Item2 + "'],";
}
The code works OK, but would like to ask if there're any better ways to do that?

You can make it more compact by using Linq, string.Join and string.Format:
result = string.Join(",", list.Select(t => string.Format("[ '{0}', '{1}']", t.Item1, t.Item2)));

You can do it using linq and string interpolation like this:
string.Join(", ", list.Select(t => $"['{t.Item1}', '{t.Item2}']"));

There are some benchmarking (note: each word contains one link, but one of the best reference I think is this.) on how to join the string.
Quote from the reference:
Rico Mariani, the .NET Performance guru, had an article on this very
subject. It's not as simple as one might suspect.
You could take a look on string.Concat and string.Builder in particular, they are usually faster than + operator.
Here I use string.Concat:
string str = string.Concat(new string[] { "[ '", list[i].Item1, "', '", list[i].Item2, "']," });

This might also do the trick for you
var input = new List<Tuple<string, string>>
{
Tuple.Create("A", "1"),
Tuple.Create("B", "2"),
Tuple.Create("C", "3")
};
string tpljoined = string.Join(", ",
input.Select(x => "['" + x.Item1 + "','" + x.Item2 + "']"));

You can also use LINQ:
var input = new List<Tuple<string, string>> { Tuple.Create("A", "1"), Tuple.Create("B", "2") };
var result = String.Join(",", input.Select(elem => "[ '" + elem.Item1 + "', '" + elem.Item2 + "']"));
Console.WriteLine(result);

Related

Use Select method to traverse an IEnumerable in C#

I have the following method that I use to traverse collections like IQueryCollection, IHeadersDictionary and IFormCollection
public static string ToString(IEnumerable<KeyValuePair<string, StringValues>> dic)
{
string res = "";
foreach (var item in dic)
{
res += item.Key + "=" + item.Value + "&";
}
return res.TrimEnd('&');
}
I was wondering if it would be possible to do it in a more " functional" style, using something like Select and String.Join method
I'm using dot-net-core 2.0
Yes you can write it using a select, it's actually quite simple:
public static string ToString(IEnumerable<KeyValuePair<string, StringValues>> dic)
{
return string.Join("&", dic.Select(_ => $"{_.Key}={_.Value}"));
}
Will it perform better, hard to say without testing, your version uses string concatenations which are probably not a good idea for a large number of string (StringBuilder) would be better. But I expect string.Join to do a better job than your version.
You have a few options:
Using Aggregate
dic.Aggregate((res, item) => res + item.Key + "=" + item.Value + "&")
.TrimEnd('&')
Using Select and string.Join
string.Join("&", dic.Select(item => item.Key + "=" + item.Value))
Using Zip and string.Join if you are using a Dictionary instance instead of a list of KeyValuePairs:
string.Join("&", dict.Keys.Zip(dict.Values, (key, value) => key + "=" + value))
You can use
var result = from keyvaluepair in dictionary
from value in keyvaluepair .Value
select keyvaluepair .Key + "=" + value;
or try aggregate,
string result = values.Aggregate("",
(key, pair) =>
key + "=" + pair.Key + ":"
+ pair.Value.Aggregate("",
(str, val) => str + "=" + val)
);
There is already a post related to same in How do I combine the keys and values of a Dictionary into one List using LINQ?

FileDialog filter - LINQ concatenation

While creating service to display OpenFileDialog/SaveFileDialog, I was thinking about creating LINQ query/clear C# code to Concatinate()/Join() filter expression.
Do the filter based on this call:
string res = "";
if(new Service().ShowOpenFileDialog(out res,
new string[]{ "JPG", "TXT", "FBX"},
new string[]{ "Images", "TextFile", "FilmBox"}))
Console.WriteLine(res); //DisplayResult
Example definition:
public bool ShowOpenFileDialog(out string result, string[] ext, string[] desc)
{
if(ext.Length != desc.Length) return false;
OpenFileDialog diag = new OpenFileDialog();
// problematic part
// diag.Filter = "Text File (*.txt)|*.txt";
// diag.Filter = desc[0] + " (*." + ext[0] + ")|*." + ext[0];
// diag.Filter += "|"+desc[1] + " (*." + ext[1] + ")|*." + ext[1];
// I tried something like:
// diag.Filter = String.Join("|", desc.Concat(" (*." + ext[0] + ")|*." + ext[0]));
// but not sure how to pass indexes across LINQ queries
diag.Filter = /* LINQ? */
if(diag.ShowDialog() == true)
{
result = diag.FileName;
return true;
}
return false;
}
Question: Is it possible to create LINQ to concatenate/join 2 arrays in such format? Is it needed to do it by code? If so, what is the cleanest/least expensive solution?
Note: As a filter (result) example:
"Images (*.JPG)|*.JPG |TextFile (*.TXT)|*.TXT |FilmBox (*.FBX)|*.FBX"
EDIT: Also please consider there might be n items in the arrays.
You should use Select to iterate over your collection. Also, string interpolation comes in handy here.
string filter = string.Join
( "|"
, ext.Zip
( desc
, (e, d) => new
{ Ext = e
, Desc = d
}
)
.Select(item => $"{item.Desc} (*.{item.Ext})|*.{item.Ext}")
);

Replacing a Char or part of a string to conform with an SQL query

I know I've not gone about this in the easiest of manners but i'm fairly new to C#.
I'm trying to make sure that when I select from only 1,2,3 or 4 of the 5 checked list boxes that i do not end up with the following
&& or &&& etc... I would like the final string to be xxxxx&xxxxx&xxx or similar as the String is added to a preset SQL query.
Code is below:
any help would be appreciated I've had a look around online for some help but not found much I was able to get my head round.
List<object> list = checkedListBox1.CheckedItems.OfType<object>().ToList();
List<object> list2 = checkedListBox2.CheckedItems.OfType<object>().ToList();
List<object> list3 = checkedListBox3.CheckedItems.OfType<object>().ToList();
List<object> list4 = checkedListBox4.CheckedItems.OfType<object>().ToList();
List<object> list5 = checkedListBox5.CheckedItems.OfType<object>().ToList();
string selected_fields_cb1 = string.Join(" ", list.ToArray());
string selected_fields_cb2 = string.Join(" ", list2.ToArray());
string selected_fields_cb3 = string.Join(" ", list3.ToArray());
string selected_fields_cb4 = string.Join(" ", list4.ToArray());
string selected_fields_cb5 = string.Join(" ", list5.ToArray());
string allSelected = (selected_fields_cb1 + " " + selected_fields_cb2 + " " + selected_fields_cb3 +
" " + selected_fields_cb4 + " " + selected_fields_cb5 + "");
string allSelected2 = allSelected.Replace( " ", "&" );
string allSelected3 = allSelected2.TrimEnd('&');
If I understand well, you try to add spaces and then replace these spaces by &.
It would be easier to do this directly.
List<object> list = checkedListBox1.CheckedItems.OfType<object>().ToList();
List<object> list2 = checkedListBox2.CheckedItems.OfType<object>().ToList();
List<object> list3 = checkedListBox3.CheckedItems.OfType<object>().ToList();
List<object> list4 = checkedListBox4.CheckedItems.OfType<object>().ToList();
List<object> list5 = checkedListBox5.CheckedItems.OfType<object>().ToList();
var allObjects = list.Concat(list2).Concat(list3).Concat(list4).Concat(list5);
var res = string.Join("&", allObjects);

C# - Advanced foreach statements?

I currently have:
string settings = "setting1:value1;setting2:value2";
string[] pair;
foreach(string setting in settings.Split(';'))
{
pair = setting.Split(':');
MessageBox.Show(pair[0] + ":" + pair[1]);
}
I would something more along the lines of:
string settings = "setting1:value1;setting2:value2";
foreach (string[] pair in string setting.Split(':') in settings.Split(';'))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
The two in keywords seem a bit ridiculous, but I would think something like this would be possible and very easy, I just don't know how.
So, is it possible?
I'm not sure this is more readable, but you asked for it and I think it looks cool ;-)
string settings = "setting1:value1;setting2:value2";
foreach(var pair in settings.Split(';').Select(str => str.Split(':')))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
(I haven't compiled it, so I'm sorry if there are syntax errors)
As an alternative to the other posted answers, you can also use the LINQ syntax:
string settings = "setting1:value1;setting2:value2";
foreach(string[] pair in
from setting in settings.Split(';')
select setting.Split(':'))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
foreach (string[] pair in settings.Split(';').Select(setting => setting.Split(':')))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
foreach (string settingstr in settings.Split(';'))
{
string[] setval = settingstr.Split(':');
string setting = setval[0];
string val = setval[1];
}

Nested foreach loop slow

The following piece of code achives the desired results, but performance is extremely slow:
SearchResultCollection absaUsers = ABSAds.FindAll();
SearchResultCollection srcUsers = ds.FindAll();
foreach (SearchResult users in srcUsers)
{
string cn = users.Properties["cn"][0].ToString();
string sn = users.Properties["sn"][0].ToString();
string userID = users.Properties["uid"][0].ToString();
string description = users.Properties["PersonnelAreaDesc"][0].ToString();
string jobCodeID = users.Properties["JobcodeID"][0].ToString();
string CostCentreID = users.Properties["costCentreID"][0].ToString();
string CostCentreDescription = users.Properties["CostCentreDescription"][0].ToString();
string givenName = users.Properties["givenName"][0].ToString();
string employmentStatus = users.Properties["EmploymentStatus"][0].ToString();
string EmploymentStatusDescription = users.Properties["EmploymentStatusDescription"][0].ToString();
foreach (SearchResult absaUser in absaUsers)
{
string absaUID = absaUser.Properties["uid"][0].ToString();
string absaEmploymentStatus = absaUser.Properties["EmploymentStatus"][0].ToString();
string absaEmploymentStatusDescription = absaUser.Properties["EmploymentStatusDescription"][0].ToString();
string absaEmployeeNumber = absaUser.Properties["employeeNumber"][0].ToString();
if (absaUID == cn && absaEmployeeNumber==userID)
{
Console.WriteLine("User Record Found:" + cn);
sw.WriteLine("Modify" + "," + cn + "," + description + "," + userID + "," + givenName + "," + sn + "," + jobCodeID + "," + CostCentreID + "," + CostCentreDescription + "," + sn + "," + cn + "," + employmentStatus + "," + EmploymentStatusDescription);
sw.Flush();
break;
}
}
}
It loops through 2 collections and mtaches the outer loops attributes with the inner's. Any suggestions on how I can optimise the performance?
It would be faster if you extracted all the absaUID values to a lookup first:
var lookup = absaUsers.Cast<SearchResult>()
.ToLookup(x => x.Properties["uid"][0].ToString());
Then you can just use:
foreach (SearchResult users in srcUsers)
{
string cn = users.Properties["cn"][0].ToString();
foreach (SearchResult matches in lookup[cn])
{
...
}
}
You haven't shown how absaUsers is defined - if it's a LINQ query expression, then it could be that your existing code will be going to the database on every iteration at the moment - whereas the above won't. On the other hand, if srcUsers is also a LINQ query expression talking to a database, you should consider doing all the matching at the database using a join instead.
you could use LINQ join, some examples are here, I'm assuming whoever built it into .NET found a pretty optimal way of doing that, and then loop through that. on a sidenote: what are your collection types? please add their declaration to the code snippet.
Use Lamda expressions:
Below is the sample one , You can optizime this to another level.
List<SearchResult> allResultGroups=new List<SearchResult>();
foreach (SearchResult absaUser in absaUsers)
{
resultGroups = srcUsers.Where(g => g.cn == absaUser.absaUID && absaUser.absaEmployeeNumber==g.userID ).ToList();
}

Categories