This is zero based index and the example is one based index, can add one if need to match. I didn't do timing test to see if this is faster or even look at memory consumptions. To me this reads and makes it easier to maintain. I prefer maintenance over performance unless it's needs to be performance skewed for the area of code it's in.
SortedList takes two values but we don't care about the value so just toss in a bool to make it happy. Then using the IndexOfKey method that uses a binary search. Which under the covers uses Array.BinarySearch. Could take SortedList out of the picture and use Array.BinarySearch to do similar to what SortListed is doing if having the bool value that isn't used is a deal breaker for you.
public static int[] Positions(params int[] items)
{
var sortedList = new SortedList<int, bool>(items.Length);
for (var i = 0; i < items.Length; i++)
{
sortedList.TryAdd(items[i], false);
}
var result = new int[items.Length];
for (var i = 0; i< items.Length; i++)
{
result[i] = sortedList.IndexOfKey(items[i]);
}
return result;
}
EDIT: If you want to avoid SortedList you can do what it's doing pretty simple.
public static IEnumerable<int> Position(params int[] items)
{
var distinct = new HashSet<int>(items);
var clone = new int[distinct.Count];
distinct.CopyTo(clone);
Array.Sort(clone);
for (var i = 0; i < items.Length; i++)
{
yield return Array.BinarySearch(clone, items[i]) + 1;
}
}