22

Javascriptで配列の要素をランク付けするアルゴリズムが必要です。

例:次のような配列があります。

[79, 5, 18, 5, 32, 1, 16, 1, 82, 13]

エントリを値でランク付けする必要があります。したがって、ランク、ランクなど82を受け取る必要があります。2つのエントリの値が同じである場合、それらは同じランクを受け取り、低い値のランクが上がります。1792

したがって、この配列の場合、新しいランキング配列は次のようになります。

[2, 7, 4, 7, 3, 9, 5, 9, 1, 6] 

これどうやってするの?

4

11 に答える 11

44

var arr = [79, 5, 18, 5, 32, 1, 16, 1, 82, 13];
var sorted = arr.slice().sort(function(a,b){return b-a})
var ranks = arr.map(function(v){ return sorted.indexOf(v)+1 });
console.log(ranks);

結果 :

[2, 7, 4, 7, 3, 9, 5, 9, 1, 6]

古いブラウザと互換性を持たせたい場合は、indexOfとmapのシムを定義する必要があるかもしれません(非常に大きな配列に対してこれを非常に高速に実行したい場合は、ループを使用し、オブジェクトをマップとして使用する方がよいことに注意してくださいの代わりに)。forindexOf

于 2013-02-12T14:17:00.420 に答える
9

ECMAScript 5の機能を使用しているため、これは古いブラウザでは機能しませんが、非常に大きな配列の場合でも、ランキングの配列をすばやく簡潔に作成できます。(indexOf線形検索を行うものは使用しないため、大きな配列の場合は遅くなる可能性があります。)

function cmp_rnum(a,b) {
    // comparison function: reverse numeric order
    return b-a;
}
function index_map(acc, item, index) {
    // reduction function to produce a map of array items to their index
    acc[item] = index;
    return acc;
}
function ranks(v) {
    var rankindex = v.slice().sort(cmp_rnum).reduceLeft(index_map, Object.create(null));
    // reduceLeft() is used so the lowest rank wins if there are duplicates
    // use reduce() if you want the highest rank
    return v.map(function(item){ return rankindex[item]+1; });
}

出力例:

> ranks([79, 5, 18, 5, 32, 1, 16, 1, 82, 13]);
  [2, 7, 4, 7, 3, 9, 5, 9, 1, 6]
于 2013-02-12T15:14:33.283 に答える
4
function rank(arr, f) {
    return arr
    .map((x, i) => [x, i])
    .sort((a, b) => f(a[0], b[0]))
    .reduce((a, x, i, s) => (a[x[1]] =
        i > 0 && f(s[i - 1][0], x[0]) === 0 ? a[s[i - 1][1]] : i + 1, a), []);
}

使用法:

rank([79, 5, 18, 5, 32, 1, 16, 1, 82, 13], (a, b) => b - a);
// [2, 7, 4, 7, 3, 9, 5, 9, 1, 6] 

少し見苦しいように見えますが、オブジェクト/マップを使用しないため、実行速度が少し速くなるだけでなく、さらに重要なことに、比較関数indexOf()で定義された「同じランク」の意味を尊重します。またはオブジェクトを使用する場合、「同じランク」はまたはを意味するだけです。indexOf()a === bString(a) === String(b)

または、次を使用しますfindIndex()

function rank(arr, f) {
    const sorted = arr.slice().sort(f)
    return arr.map(x => sorted.findIndex(s => f(x, s) === 0) + 1)
}
于 2016-02-19T07:56:12.833 に答える
2

JavaScriptES6の単純な2行のソリューション。

var arrayRankTransform = arr => {
  const sorted = [...arr].sort((a, b) => b - a);
  return arr.map((x) => sorted.indexOf(x) + 1);
};

console.log(arrayRankTransform([79, 5, 18, 5, 32, 1, 16, 1, 82, 13]));

于 2020-09-28T03:49:09.317 に答える
1

私はJavascriptが得意ではありませんが、PHPでは次の方法で非常に簡単に実行できます。JavaScriptが得意な人なら、関連するコードを思い付くことができます。

$marks = [79, 5, 18, 5, 32, 1, 16, 1, 82, 13];

public function getRank($marks) {
    $rank = 1; $count = 0; $ranks = [];
    //sort the marks in the descending order
    arsort($marks,1);
    foreach($marks as $mark) {
      //check if this mark is already ranked
      if(array_key_exists($mark, $ranks)) {
       //increase the count to keep how many times each value is repeated
       $count++;
       //no need to give rank - as it is already given
      } else {
        $ranks[$mark] = $i+$j;
        $i++;
      }
    return $ranks;
}
于 2014-07-27T12:35:53.557 に答える
0

私が書いていた操作スケジューリングスクリプトにも同じコードが必要でした。オブジェクトとそのプロパティ/キーを使用しました。これらは任意の値を持ち、必要なときにいつでもアクセスできます。また、いくつかの記事を読んだ限り、オブジェクト内のプロパティの検索は、配列内の検索よりも高速である可能性があります。

以下のスクリプトには、3つの簡単なステップがあります。

  1. 値を並べ替えます(スクリプトの残りの部分では、昇順または降順は関係ありません)

  2. 各値のランクと出現回数を見つける

  3. 手順2のデータを使用して、指定された値をランクに置き換えます

ノート!以下のスクリプトは重複するランクを出力しませんが、代わりに重複する値/要素のランクをインクリメントします。

function rankArrayElements( toBeRanked ) {

// STEP 1
var toBeRankedSorted = toBeRanked.slice().sort( function( a,b ) { return b-a; } ); // sort descending
//var toBeRankedSorted = toBeRanked.slice().sort( function( a,b ) { return a-b; } ); // sort ascending

var ranks = {}; // each value from the input array will become a key here and have a rank assigned
var ranksCount = {}; // each value from the input array will become a key here and will count number of same elements

// STEP 2
for (var i = 0; i < toBeRankedSorted.length; i++) { // here we populate ranks and ranksCount
    var currentValue = toBeRankedSorted[ i ].toString();

    if ( toBeRankedSorted[ i ] != toBeRankedSorted[ i-1 ] ) ranks[ currentValue ] = i; // if the current value is the same as the previous one, then do not overwrite the rank that was originally assigned (in this way each unique value will have the lowest rank)
    if ( ranksCount[ currentValue ] == undefined ) ranksCount[ currentValue ] = 1; // if this is the first time we iterate this value, then set count to 1
    else ranksCount[ currentValue ]++; // else increment by one
}

var ranked = [];

// STEP 3
for (var i = toBeRanked.length - 1; i >= 0; i--) { // we need to iterate backwards because ranksCount starts with maximum values and decreases
    var currentValue = toBeRanked[i].toString();

    ranksCount[ currentValue ]--;
    if ( ranksCount[ currentValue ] < 0 ) { // a check just in case but in theory it should never fail
        console.error( "Negative rank count has been found which means something went wrong :(" );
        return false;
    }
    ranked[ i ] = ranks[ currentValue ]; // start with the lowest rank for that value...
    ranked[ i ] += ranksCount[ currentValue ]; // ...and then add the remaining number of duplicate values
}

return ranked;}

また、スクリプトのために何か他のことをする必要がありました。

上記の出力の意味は次のとおりです。

  • index-入力配列の要素のID

  • value-入力配列からの要素のランク

そして、基本的に「インデックスを値と交換する」必要がありました。これにより、要素IDのリストが、ランク順に並べられます。

function convertRanksToListOfElementIDs( ranked ) {  // elements with lower ranks will be first in the list

var list = [];

for (var rank = 0; rank < ranked.length; rank++) { // for each rank...
    var rankFound = false;
    for (var elementID = 0; elementID < ranked.length; elementID++) { // ...iterate the array...
        if ( ranked[ elementID ] == rank ) { // ...and find the rank
            if ( rankFound ) console.error( "Duplicate ranks found, rank = " + rank + ", elementID = " + elementID );
            list[ rank ] = elementID;
            rankFound = true;
        }
    }
    if ( !rankFound ) console.error( "No rank found in ranked, rank = " + rank );
}

return list;}

そしていくつかの例:

ToBeRanked:

[36、33、6、26、6、9、27、26、19、9]

[12、12、19、22、13、13、7、6、13、5]

[30、23、10、26、18、17、20、23、18、10]

[7、7、7、7、7、7、7、7、7、7]

[7、7、7、7、7、2、2、2、2、2]

[2、2、2、2、2、7、7、7、7、7]

[0、1、2、3、4、5、6、7、8、9]

rankArrayElements(ToBeRanked):

[0、1、8、3、9、6、2、4、5、7]

[5、6、1、0、2、3、7、8、4、9]

[0、2、8、1、5、7、4、3、6、9]

[0、1、2、3、4、5、6、7、8、9]

[0、1、2、3、4、5、6、7、8、9]

[5、6、7、8、9、0、1、2、3、4]

[9、8、7、6、5、4、3、2、1、0]

convertRanksToListOfElementIDs(rankArrayElements(ToBeRanked)):

[0、1、6、3、7、8、5、9、2、4]

[3、2、4、5、8、0、1、6、7、9]

[0、3、1、7、6、4、8、5、2、9]

[0、1、2、3、4、5、6、7、8、9]

[0、1、2、3、4、5、6、7、8、9]

[5、6、7、8、9、0、1、2、3、4]

[9、8、7、6、5、4、3、2、1、0]

于 2016-08-28T22:33:58.783 に答える
0

ここでの私見のいくつかの解決策は、繰り返される値の後に発生する値を正しく処理しないため、正しくありません。そのようなフォロワーは次のランクを取得する必要があります。最高ランクは、配列内の一意の値の数と等しくなければなりません。このソリューション(PHP)は、私見では正しいです。基本的に、バグが削除された@Sureshのソリューション。

  function rank($marks){
    $rank = 1; $ranks = [];
    rsort($marks,SORT_NUMERIC);
    foreach($marks as $mark) {
      if(!isset($ranks[$mark])) {
        $ranks[$mark] = $rank++;
      }
    }
    return $ranks;
   }
于 2019-01-08T01:20:12.670 に答える
0

これは、配列内の重複するキーで機能するはずです

function rank(arry) {
    let sorted = arry.slice().sort(function (a, b) {
        return b - a
    });


    let currentRank = sorted.length;
    let rankValue = null;
    let ranks = [];

    sorted.forEach(value => {
        if(value !== rankValue && rankValue !==null) {
            currentRank--;
        }

        ranks.push({value,currentRank});
        rankValue = value;
    });

    let mapRanksToArrayValues = arry.map(function (x) {
        let _rank = null;
        ranks.forEach( rank => {
            if(rank.value === x ) {
                _rank =  rank.currentRank;
                return;
            }
        });
        return _rank;
    });

    return mapRanksToArrayValues;
}
于 2019-03-04T19:01:03.120 に答える
0

Rank_JSProを作成しました。

<script>https://cdn.statically.io/gl/maurygta2/mquery/master/Rank Tools/rank.js</script>

基本的な方法:

var a = {
  b: 2,
  c: 7
}
Rank_Tools.rank(a,(pos,name,value) => {
  return pos + ". "+name+" "+value;
})
// result
// rank1 = 1. c 7
// rank 2 = 2. b 2
于 2019-06-14T22:57:22.707 に答える
0

この代替方法では、入力配列を並べ替える必要はありません。

// O(n^2)
const rank = (arr) => {
  // Create a temporary array to keep metadata 
  // regarding each entry of the original array
  const tmpArr = arr.map(v => ({
    value: v,
    rank: 1,
  }));

  // Get rid of douplicate values
  const unique = new Set(arr);

  // Loops through the set
  for (let a of unique) {
    for (let b of tmpArr) {
      // increment the order of an element if a larger element is pressent
      if (b.value < a) {
        b.rank += 1;
      }
    }
  }

  // Strip out the unnecessary metadata 
  return tmpArr.map(v => v.rank);
};

console.log(rank([2600, 200, 36, 36, 400, 2, 0, 0]));
// => [1, 3, 4, 4, 2, 5, 6, 6]

console.log(rank([79, 5, 18, 5, 32, 1, 16, 1, 82, 13]));
// => [2, 7, 4, 7, 3, 8, 5, 8, 1, 6]

于 2020-04-28T16:00:29.233 に答える
0

私は同じ宿題をしました、そしてこれはうまくいきます、そしてあなたがこれに不慣れであるならばまた理解するのはより簡単です。

function rankings(arr) {
    let rankingsArr = [];
    for (let i = 0; i < arr.length; i++) {
        var rank = 1;
        for (let j = 0; j < arr.length; j++) {
            if (arr[j] > arr[i]) rank++;
        }
        rankingsArr.push(rank);
    }
    return rankingsArr;
}
于 2020-07-10T18:07:17.563 に答える