You can work this out by considering the types in play. For example, MapToLocalObject – when viewed as an asynchronous function – does map from R to L. But if you view it as a synchronous function, it maps from R to Task<L>.
Task is a “future”, so Task<L> can be thought of as a type that will produce an L at some point in the future.
So you can easily convert from a sequence of R to a sequence of Task<L>:
IEnumerable<Task<L>> mappingTasks = remoteItems.Select(remoteItem => MapToLocalObject(remoteItem));
Note that there is an important semantic difference between this and your original code. Your original code waits for each object to be mapped before proceeding to the next object; this code will start all mappings concurrently.
Your result is a sequence of tasks – a sequence of future L results. To work with sequences of tasks, there are a few common operations. Task.WhenAll and Task.WhenAny are built-in operations for the most common requirements. If you want to wait until all mappings have completed, you can do:
L[] mappedItems = await Task.WhenAll(mappingTasks);
If you prefer to handle each item as it completes, you can use OrderByCompletion from my AsyncEx library:
Task<L>[] orderedMappingTasks = mappingTasks.OrderByCompletion();
foreach (var task in orderedMappingTasks)
{
var mappedItem = await task;
...
}