JavaScript中与numpy argsort等价的是什么?

13

我想按点击次数对imgUrl数组进行排序。我有两个数组。

clickCount = [5,2,4,3,1]
imgUrl     = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg']

在numpy中很容易实现。我使用 order = np.argsort(clickCount) 然后创建另一个数组 newArray = [imgUrl[i] for i in order]

如何在JavaScript中实现相同的效果(最好是纯JS)?

3个回答

16
你可以在Python中使用Schwartzian transform,也称为Decorate-Sort-Undecorate(DSU)。 DSU:
  1. Decorate - 使用Array#Map为数组中的每个项添加所需的排序数据
  2. Sort - 使用添加的数据进行排序
  3. Undecorate - 再次使用Array#map提取排序后的数据
Demo:

const dsu = (arr1, arr2) => arr1
  .map((item, index) => [arr2[index], item]) // add the args to sort by
  .sort(([arg1], [arg2]) => arg2 - arg1) // sort by the args
  .map(([, item]) => item); // extract the sorted items

const clickCount = [5,2,4,3,1];
const imgUrl = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg'];

const result = dsu(imgUrl, clickCount);
  
console.log(result);

感谢 dankal444 对函数进行的重构


没问题,但我的意思是让这个函数类似于 numpy.argsort - 以单个数组作为输入,以索引作为输出。解决“什么是numpy argsort的javascript等效方法?”而不是针对OP的具体问题。 - dankal444
我已经将它变得更加通用,但如果你想让它类似于 numpy.argsort,你需要将其添加到数组的原型中。你的版本实际上并没有起作用,因为你忽略了 2n 数组。你应该创建一个更新数组原型的新答案,并创建一个片段,这样你就知道它是有效的。 - Ori Drori
好的,将这样的功能添加到原型中是很好的,但为什么它是必要的呢?这不是“我的版本”,只是要添加到您的答案中的内容。而且“不起作用”是因为它不应该解决OP问题。它只是一个类似于numpy.argsort的函数,基于您的原始答案。如果您真的觉得不合适,我会添加我的答案。 - dankal444
这实际上并不是。我的答案特别处理使用另一个数组进行排序的情况。你创建了一个返回原始索引的版本。你正在以非常特定的方式使用DSU。那是另一个答案。没有必要添加任何内容到原型中来完成这个操作。我的错误。 - Ori Drori
你能解释一下 ([arg1], [arg2]) => arg2 - arg1 是如何工作的吗?我知道它是在链接中的比较函数,但我不确定它如何应用于 [arr2[index], item] - elexhobby
排序比较两个项目。由于每个项目都被映射为 [arr2[index], item]),我们将要比较的项目中的 arr2[index] 分配给 arg1arg2 - Ori Drori

6

为了完整起见,这是我的解决方案(提供 argsort 函数),通过扩展 Ori 的答案以使用 DSU 来实现。 由于 sort 默认采用第一个元素,因此将其实现为 DSU 只需添加索引,对其进行排序,然后获取索引即可。

let decor = (v, i) => [v, i];          // set index to value
let undecor = a => a[1];               // leave only index
let argsort = arr => arr.map(decor).sort().map(undecor);

clickCount = [5, 2, 4, 3, 1]
imgUrl = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']

order = argsort(clickCount);
newArray = order.map(i => imgUrl[i])

console.log(newArray);


argsort= a=>a.map(d).sort().map(u);d=(v,i)=>[v,i];u=i=>i[1] - Eran W
a=>a.map((v,i)=>[v,i]).sort().map(i=>i[1]) :43个字符 - Eran W

0

函数式编程方式(如@Ori Drori的代码)总是很迷人,但在这种情况下,您只需要重新排列数组的元素。我相信有一种更简单的方法,而且代码阅读起来更容易。

const clickCount = [5,2,4,3,1];
const imgUrl = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg'];

sortByArrayRefOrder = (data, orderRefArr) => {
 let orderedArr = [], i=0;
 orderRefArr.map( o => { orderedArr[o-1] = data[i++]});
 return orderedArr.reverse();
}

console.log ( sortByArrayRefOrder(imgUrl, clickCount) );


不好意思,如果我的示例有误导性的话。点击计数是指点击次数,而不是有序引用。点击计数也可以像这样 const clickCount = [5323,23545,4333,34,123]; - Souradeep Nanda
1
哦,好吧,在这种情况下@Ori Drori的答案是完美的答案!对于搞砸的事情感到抱歉。 - JohnPan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接