I have a list of string that contains for example the following items:
0$1, 0$2, 0$5, 1$1, 1$8
My will is remove the other items with $1 if one already exists. In that example, the expected output would be:
0$1, 0$2, 0$5, 1$8
Is there a cleaner way to achieve this, with LINQ or anything else, rather than doing something like this?
For Each str As String In ddlElecDBFilter.SelectedItemsList
Dim currentString As String = str
'DO A FOR EACH LOOP on the other elements (starting from the current index 1 and delete them
Next
Thank you in advance
CodePudding user response:
Not sure if there is a "cleaner" way to do this:
Dim input As String = "0$1, 0$2, 0$5, 1$1, 1$8"
Dim uniqueValues As New List(Of String)
input.Split(", ".ToCharArray, StringSplitOptions.RemoveEmptyEntries) _
.Where(Function(x) x.Contains("$")) _
.Select(Function(y) New KeyValuePair(Of String, String)(y.Substring(y.IndexOf("$")), y)) _
.ToList() _
.ForEach(Sub(pair)
If Not uniqueValues.Any(Function(x) x.EndsWith(pair.Key)) Then
uniqueValues.Add(pair.Value)
End If
End Sub)
Dim output As String = String.Join(", ", uniqueValues)
CodePudding user response:
Since you said C# was acceptable, here my answer is for C#. If you have trouble translating to VB.Net, I can add that.
I would not say that LINQ is cleaner, but it is short. When you need to accumulate items, Aggregate
is the method to use. When you need to keep some type of state while processing, Aggregate
with a ValueTuple
(or some other container) allows you to preserve a value while processing.
If ss
contains your List<string>
, then ans
will contain the processed strings:
var ans = ss.Select(s => s.Split(", ")
.Aggregate((ans: Enumerable.Empty<string>(), seen: false), // accumulate result in ans, track whether $1 has been seen
(ans_seen, item) => ans_seen.seen
? (item.EndsWith("$1") ? ans_seen : (ans_seen.ans.Append(item), ans_seen.seen))
: (ans_seen.ans.Append(item), item.EndsWith("$1"))
)
.ans.Join(", ")) // string extension method that encapsulates String.Join
.ToList();
This uses an obvious string extension method to encapsulate String.Join
.
I would say it is better to create a function that uses looping and just use LINQ for the List
processing:
public static class StringExt {
public static string KeepOnlyFirstDollarOne(this string s) {
var seen = false;
var resultList = new List<string>();
foreach (var item in s.Split(", ")) {
if (seen) {
if (!item.EndsWith("$1"))
resultList.Add(item);
}
else {
resultList.Add(item);
seen = item.EndsWith("$1");
}
}
return String.Join(", ", resultList);
}
}
Then getting an answer is as simple as:
var ans = ss.Select(s => s.KeepOnlyFirstDollarOne()).ToList();