3

I am looking for a version of argsort, such as exists in numpy or in fortran. Is there an implementation of argsort in Nim ... or accessible to Nim in some library? It seems a bit surprising that it is missing.

UPDATE

The following seems to work for argsort:

proc argsort[T](a : T) : seq[int] =
  result = toSeq(0..a.len - 1)
  sort(result, proc (i, j: int): int = cmp(a[i], a[j]))

Presumably, though, it could be more efficient written natively and avoiding the function pointer....

Agi Hammerthief
  • 2,114
  • 1
  • 22
  • 38
shaunc
  • 5,317
  • 4
  • 43
  • 58
  • If you've found a solution to this, I suggest writing an answer so that this question can be closed. – squirl Jun 29 '16 at 13:40
  • @Samadi - The update suggests a workaround... but perhaps having an open question might inspire someone to write a wrapper around a native implementation? Or is it more important to have a closed question? – shaunc Jul 02 '16 at 01:42
  • That's a good point @shaunc, I hadn't thought of that. – squirl Jul 02 '16 at 14:54
  • whats not "native" about that implementation? it's better than my answer! – shirleyquirk Sep 20 '20 at 08:42

1 Answers1

3

It hasn't made it's way into nimble yet, but Arraymancer has an argsort here

import arraymancer,algorithm,sequtils

proc argsort*[T](t: Tensor[T], order = SortOrder.Ascending): Tensor[int] =
  ## Returns the indices which would sort `t`. Useful to apply the same sorting to
  ## multiple tensors based on the order of the tensor `t`.
  ##
  ## Sorts the raw underlying data!
  # TODO: should we clone `t` so that if `t` is a view we don't access the whole
  # data?
  assert t.rank == 1, "Only 1D tensors can be sorted at the moment!"
  proc cmpIdxTup(x, y: (T, int)): int = system.cmp(x[0], y[0])
  # make a tuple of input & indices
  var tups = zip(toOpenArray(t.storage.Fdata, 0, t.size - 1),
                 toSeq(0 ..< t.size))
  # sort by custom sort proc
  tups.sort(cmp = cmpIdxTup, order = order)
  result = newTensorUninit[int](t.size)
  for i in 0 ..< t.size:
    result[i] = tups[i][1]

let x = @[3,9,4,1,5].toTensor()

echo x.argsort()

produces:

Tensor[system.int] of shape [5]" on backend "Cpu"
    3   0   2   4   1

try it out here

shirleyquirk
  • 1,527
  • 5
  • 21