I have a legacy code in which ids
List has some duplicate value coming and this method is being called from lot of difference places as of now -
public async Task<List<T>> Execute<T>(IList<int> ids, Policy policy, Func<CancellationToken, int, Task<T>> mapperFunc) where T : class
{
var holder = new List<Task<T>>(ids.Count);
var removeNull = new List<T>(ids.Count);
for (int i = 0; i < ids.Count; i++)
{
var id = ids[i];
holder.Add(ProcessData(policy, ct => mapperFunc(ct, id)));
}
var responses = await Task.WhenAll(holder);
for (int i = 0; i < responses.Length; i++)
{
var response = responses[i];
if (response != null)
{
removeNull.Add(response);
}
}
return removeNull;
}
I am trying to change above method such that I can remove duplicate stuff from ids
list so I came up with below code which does that but I wanted to see if there is any better way we can write below code?
public async Task<List<T>> Execute<T>(IList<int> ids, Policy policy, Func<CancellationToken, int, Task<T>> mapperFunc) where T : class
{
var noDupsList = new HashSet<int>(ids).ToList();
var holder = new List<Task<T>>(noDupsList.Count);
var removeNull = new List<T>(noDupsList.Count);
for (int i = 0; i < noDupsList.Count; i++)
{
var id = noDupsList[i];
holder.Add(ProcessData(policy, ct => mapperFunc(ct, id)));
}
var responses = await Task.WhenAll(holder);
for (int i = 0; i < responses.Length; i++)
{
var response = responses[i];
if (response != null)
{
removeNull.Add(response);
}
}
return removeNull;
}
Update
Seeing the answer that came I thought it's good idea to mention how my actual code is - This is how my original code is :
public async Task<List<T>> Execute<T>(IList<int> ids, Policy policy, Func<CancellationToken, int, Task<T>> mapperFunc, string logMessage) where T : class
{
var noDupsList = new HashSet<int>(ids).ToList();
var holder = new List<Task<T>>(noDupsList.Count);
var removeNull = new List<T>(noDupsList.Count);
using (var logMetric = new LogMetric(_logger, TITLE, "DatabaseCall"))
{
logMetric.Message = logMessage;
for (int i = 0; i < noDupsList.Count; i++)
{
var id = noDupsList[i];
holder.Add(ProcessData(policy, ct => mapperFunc(ct, id)));
}
var responses = await Task.WhenAll(holder);
for (int i = 0; i < responses.Length; i++)
{
var response = responses[i];
if (response != null)
{
removeNull.Add(response);
}
}
logMetric.StatusCode = (removeNull.Count == 0) ? 204 : 200;
}
return removeNull;
}
Linq
it will shorten your code and give you more readability to your code. For instance,var uniqueIdsList = ids.Distinct().ToList();
would give you the unique ids directly. \$\endgroup\$Linq
efficient here? I have been told its quite expensive and this method will be called at hight throughput so just wanted to make sure. But apart from that do you think we can rewrite this in better way to solve this problem or just change that one line to use linq instead of set? \$\endgroup\$Linq
is efficient in mostly, it would do the same thing, except it would be shorter, readable, and extendable. You can try to test it, and see how it would preform with the reset of the code. Compare, then decide. \$\endgroup\$ProcessData
actually should do, neither do I know whether you can change the signature of your method. I would quite possibly keep the return type toTask<IEnumerable<T>>
orTask<IReadonlyList<T>>
if I have to, and the input type restricted toIEnumerable<int> ids
. To be fair you can wrap the entire code in 1 somewhat long one liner with linq with using aSelect
(to get the tasks) and aWhere
(to filter out the nulls). Is performance a must here? \$\endgroup\$logMessage
coming? Do you really want to log a number here? If you really need to know if nulls got removed, I guess you could check the hashset length vs the filtered responses length, but I am not getting the logic here completely \$\endgroup\$