V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
coderQiQin
V2EX  ›  JavaScript

js 大佬请赐教优雅算法

  •  1
     
  •   coderQiQin · 2020-07-09 11:25:44 +08:00 · 6535 次点击
    这是一个创建于 1600 天前的主题,其中的信息可能已经有所发展或是发生改变。
    let params = {
        d:9,
        i:15,
        s:3,
        c:15
      }
      // ['i','c']
      
    let params2 = {
        d:9,
        i:20,
        s:3,
        c:10
      }
      // ['i']
    

    期望返回最大值的 key 的数组, 有没有优雅方式,或者函数式

    64 条回复    2020-07-10 16:40:03 +08:00
    hackyuan
        1
    hackyuan  
       2020-07-09 11:51:25 +08:00
    写了个不优雅的
    ```js
    const maxKeys = obj => Object.entries(obj).reduce((acc, cur) => {
    const [key, value] = cur;
    if (value > acc.max) {
    acc.max = value;
    acc.list = [key];
    return acc;
    }

    if (value === acc.max) {
    acc.list.push(key);
    }

    return acc;
    }, {max: 0, list: []}).list;

    maxKeys(params); // ["i", "c"]
    ```
    fe619742721
        2
    fe619742721  
       2020-07-09 11:59:28 +08:00
    遍历一次就可以了吧
    misdake
        3
    misdake  
       2020-07-09 12:00:04 +08:00   ❤️ 15
    let max = Math.max(...Object.values(params));
    Object.keys(params).filter(key => params[key] === max) // ["i", "c"]
    aguesuka
        4
    aguesuka  
       2020-07-09 12:21:21 +08:00 via Android
    建议用循环,显然需要一个 variable 当前保存最大值,和一个 mutabl list 保存 key 。不过改成递归应该比较漂亮。
    Hanggi
        5
    Hanggi  
       2020-07-09 12:21:39 +08:00
    import _ from 'lodash'

    function getMaxKeys (obj) {
    return _.keys(obj).filter(key => obj[key] === _.max(_.values(obj)));
    }

    result = getMaxKeys(params)
    cigmax
        6
    cigmax  
       2020-07-09 12:24:08 +08:00 via iPhone
    const maxKeys = Object.entries(params).reduce((acc,cur)=>{if(cur[1]>acc[1]){return [[cur[0]],cur[1]]} else if(cur[1]===acc[1]){return [[...acc[0],cur[0]],cur[1]]}},[[],0])
    otakustay
        7
    otakustay  
       2020-07-09 12:30:08 +08:00   ❤️ 4
    const maxKeys = Object.entries(array).reduce(
    ([max, keys], [key, value]) => {
    if (value > max) {
    return [value, [key]];
    }

    if (value === max) {
    return [value, keys.concat(key)];
    }

    return [max, keys];
    },
    [-Infinity, []]
    )
    Mutoo
        8
    Mutoo  
       2020-07-09 12:32:39 +08:00
    import _ from 'lodash';

    _.chain(params).toPairs().sortBy(i => -i[1]).filter((v, _, arr) => v[1] === arr[0][1]).map(i => i[0]).value()
    musi
        9
    musi  
       2020-07-09 12:37:42 +08:00   ❤️ 1
    ```
    let getMaxKeys = obj => Object.keys(obj).map(key => obj[key] == Math.max.apply(null, Object.values(obj)) ? key : null).filter(k => k != null)
    ```

    貌似还有点不优雅。。。
    musi
        10
    musi  
       2020-07-09 12:41:49 +08:00   ❤️ 1
    @musi 把 map 直接改为 filter 就比较优雅了。
    ```
    let getMaxKeys = obj => Object.keys(obj).filter(key => obj[key] === Math.max.apply(null, Object.values(obj)))
    ```
    xrr2016
        11
    xrr2016  
       2020-07-09 12:52:58 +08:00   ❤️ 1
    Object.values(params).sort((a, b) => b - a)[0]
    Cbdy
        12
    Cbdy  
       2020-07-09 12:58:48 +08:00
    function getMaxValueKeys(params) {
    const invertedMap = Object.entries(params).reduce((a, c) => (a.set(c[1], [...(a.get(c[1]) || []), c[0]])), new Map)
    const maxKey = Math.max(...invertedMap.keys())
    return invertedMap.get(maxKey)
    }
    dartabe
        13
    dartabe  
       2020-07-09 13:03:08 +08:00
    顶一发 filter 感觉函数式有点语义化 瞎用的话没问题 但是不优雅
    dartabe
        14
    dartabe  
       2020-07-09 13:06:38 +08:00
    从算法角度 我还是觉得直接 for 吧
    yamedie
        15
    yamedie  
       2020-07-09 13:11:20 +08:00
    盲猜 7 楼最优, 更优估计就是原生 for 了
    klesh
        16
    klesh  
       2020-07-09 13:21:15 +08:00
    Object.keys(params).reduce((k, r) => params[k] > r ? params[k] : r, Number.MIN_VALUE)
    no1xsyzy
        17
    no1xsyzy  
       2020-07-09 13:49:46 +08:00
    #7 的 keys.concat(key) 可以改成 [...keys, key]
    Hanggi
        18
    Hanggi  
       2020-07-09 14:11:44 +08:00   ❤️ 6
    没看懂你们对优雅的定义。。。
    KuroNekoFan
        19
    KuroNekoFan  
       2020-07-09 14:11:48 +08:00 via iPhone
    你问的应该叫写法不叫算法
    hupo0
        20
    hupo0  
       2020-07-09 14:16:10 +08:00
    const maxKey = function (o) {
    const [r] = Object.entries(o).reduce(([r, max], [k, v]) => {
    switch (Math.sign(v - max)) {
    case -1:
    return [r, max];
    case 0:
    return r.push(k), [r, max];
    case 1:
    return [[k], v];
    }
    });
    return r;
    };
    ericgui
        21
    ericgui  
       2020-07-09 14:29:42 +08:00 via Android
    怎么写,时间复杂度都是 O(n)
    优雅不起来
    Tdy95
        22
    Tdy95  
       2020-07-09 14:40:29 +08:00
    7 楼+1,我猜楼主的意思是想代码看起来漂亮、短小点?
    renmu123
        23
    renmu123  
       2020-07-09 14:42:56 +08:00 via Android   ❤️ 1
    我觉得 for 循环最优雅间接,一眼就能看得出来在干啥
    wanguorui123
        24
    wanguorui123  
       2020-07-09 14:45:03 +08:00
    Object.entries(params).filter(item=>item[1] === Math.max(...Object.values(params))).flatMap(item=>item[0])
    aaronlam
        25
    aaronlam  
       2020-07-09 15:18:59 +08:00
    写法上的优雅应该还是 7 楼的比较优雅把
    wanguorui123
        26
    wanguorui123  
       2020-07-09 15:19:12 +08:00
    var maxKeys = params => Object.entries(params).filter(item=>item[1] === Math.max(...Object.values(params))).flatMap(item=>item[0])
    source
        27
    source  
       2020-07-09 15:46:43 +08:00
    为啥都在说 7 楼最优。。。
    reduce 的回调自由度太大了,很难一眼看出编写者的意图
    我第一反应是跟 4 楼一样(除了我是 const 拥护者以外
    source
        28
    source  
       2020-07-09 15:47:27 +08:00
    看花了,是 3 楼
    otakustay
        29
    otakustay  
       2020-07-09 15:48:39 +08:00
    @source 我同意你的说法,事实上最易读的是写个 for,想要 const 可以来个 const max = {current: 0} 玩
    写 reduce 纯粹吧……一种信仰
    tiedan
        30
    tiedan  
       2020-07-09 15:53:07 +08:00
    易读算优雅还是代码短算优雅 这是个问题
    roscoecheung1993
        31
    roscoecheung1993  
       2020-07-09 15:56:13 +08:00
    可读就 3 楼,追求效率就 for 遍历一趟
    takemeaway
        32
    takemeaway  
       2020-07-09 16:03:11 +08:00   ❤️ 1
    for 循环多简洁明了,整那么多花里胡哨的。
    jackielin
        33
    jackielin  
       2020-07-09 16:12:57 +08:00
    如果用 ramdajs 的话
    `R.reduce(R.max, -Infinity, Object.values(params))`

    可以解决
    alonehat
        34
    alonehat  
       2020-07-09 16:15:04 +08:00
    Object.entries(params).sort(function(a,b){return b[1]-a[1]}).filter(function(item,index,arr){ return item[1]==arr[0][1] }).join('').match(/[a-z]/g)

    手动滑稽
    chen90902
        35
    chen90902  
       2020-07-09 17:52:05 +08:00
    也来试一下

    ```js

    const maxKeys = (obj) =>
    Object.keys(obj).filter(
    (key, _, arr) =>
    obj[key] ===
    Math.max.apply(
    Math,
    arr.map((key) => obj[key])
    )
    );

    ```
    brucewar
        36
    brucewar  
       2020-07-09 17:54:41 +08:00
    再简洁的代码,也要保证别人或者自己回头看的时候容易理解
    gdrk
        37
    gdrk  
       2020-07-09 18:34:28 +08:00
    同意三楼,简洁可读性强。
    assassin1993zj
        38
    assassin1993zj  
       2020-07-09 18:50:57 +08:00
    @misdake 写的好啊
    autoxbc
        39
    autoxbc  
       2020-07-09 18:54:10 +08:00   ❤️ 1
    for 不够函数式
    reduce 心智负担大

    写多了就知道,这两个能不用就不用
    hanxiV2EX
        40
    hanxiV2EX  
       2020-07-09 19:07:13 +08:00
    写 for 吧, 不华丽花哨,看代码的人能一眼看出来就行。
    hanxiV2EX
        41
    hanxiV2EX  
       2020-07-09 19:18:05 +08:00
    我也写了个,没有语法糖的。

    function getMaxKeys(obj) {
    var maxKeys = [];
    var maxValue = null;
    for (var k in obj) {
    var v = obj[k];
    if (maxValue === null || v >= maxValue) {
    if (maxValue !== v) {
    maxKeys.length = 0;
    }
    maxValue = v;
    maxKeys.push(k);
    }
    }
    return maxKeys;
    }
    hanxiV2EX
        42
    hanxiV2EX  
       2020-07-09 19:24:12 +08:00
    lovecy
        43
    lovecy  
       2020-07-09 19:25:43 +08:00
    function maxKeys(obj){
    let a = [];

    for (var i in obj) {
    let v = obj[i];
    a[v] || (a[v] = []);
    a[v].push(i);
    }

    return a.pop();
    }
    大佬们轻喷(^・ω・^ )( ^・ω・^)(^・ω・^ )( ^・ω・^)
    rioshikelong121
        44
    rioshikelong121  
       2020-07-09 20:05:33 +08:00
    ```javascript
    function getMaxKeys(obj){
    let maxValue = Math.max(...Object.values(obj));
    return Object.entries(obj).reduce((total, cur) => (cur[1] === maxValue ? total.push(cur[0]) : null, total), []);
    }
    ```

    我没考虑时间复杂度。
    Shy07
        45
    Shy07  
       2020-07-09 20:43:11 +08:00
    rabbbit
        46
    rabbbit  
       2020-07-09 21:34:03 +08:00
    function getMaxKeys(obj) {
      let max = -Infinity;
      let maxKeys = [];
      for (const [key, value] of Object.entries(obj)) {
       if (max < value) {
        max = value;
        maxKeys = [key];
      } else if (max === value) {
        maxKeys.push(key);
      }
     }
      return maxKeys;
    }
    lneoi
        47
    lneoi  
       2020-07-09 23:03:44 +08:00
    Object.entries(params).reduce(
    (max, [key, val]) => ((val === max[0]) ? [max[0], [...max[1], key]] : max)
    , [Math.max(...Object.values(params)), []]
    )[1]

    来个强行一行的...
    nightcatsama
        48
    nightcatsama  
       2020-07-10 00:35:18 +08:00
    ```
    const maxKeys = params => Object.keys(params).reduce((acc, cur, _, []) => !acc.length || params[cur] > params[acc[0]] ? [cur] : params[cur] === params[acc[0]] ? acc.concat([cur]) : acc)
    ```

    写了个强行一行的,时间复杂度 On 的
    autoxbc
        49
    autoxbc  
       2020-07-10 01:53:22 +08:00
    @lovecy #43 稀疏数组,这个解法是别致的
    ericgui
        50
    ericgui  
       2020-07-10 05:08:52 +08:00
    @rabbbit 这是正解
    hejingyuan199
        51
    hejingyuan199  
       2020-07-10 07:33:16 +08:00
    我想起了 睡觉排序
    哈哈
    相当优雅
    Mutoo
        52
    Mutoo  
       2020-07-10 07:52:31 +08:00
    函数式可以非常易读,并且容易理解。

    const params = {
    d: 9,
    i: 15,
    s: 3,
    c: 15
    };

    const byValueDesc = i => -i[1];
    const byHeadValue = (v, _, arr) => v[1] === arr[0][1];
    const pickKey = i=>i[0];

    _.chain(params)
    .toPairs()
    .sortBy(byValueDesc)
    .filter(filterByHeadValue)
    .map(pickKey)
    .value()
    Mutoo
        53
    Mutoo  
       2020-07-10 07:53:24 +08:00
    @Mutoo typo: .filter(byHeadValue)
    edk24
        54
    edk24  
       2020-07-10 09:34:15 +08:00
    ```
    function getMaxKey(obj) {
    const vals = Object.values(obj)
    const max = Math.max.apply(null, vals)
    const arr = Object.entries(obj)

    const retkeys = []
    arr.forEach(item =>{
    if (item[1] == max) {
    retkeys.push(item[0])
    }
    })
    return retkeys
    }

    getMaxKey(params) // [ 'i', 'c' ]
    getMaxKey(params2) // [ 'i' ]
    ```

    不优雅的写法...
    source
        55
    source  
       2020-07-10 10:33:54 +08:00   ❤️ 1
    @autoxbc #39 完全认同
    encro
        56
    encro  
       2020-07-10 10:38:26 +08:00
    mk= null;
    for (k in params) {
    if (mk===null) {
    mk= k;
    continue;
    }
    mk= params[k]>params[mk] ? k : mk;
    }
    return mk;
    ZeroShiro
        57
    ZeroShiro  
       2020-07-10 10:38:41 +08:00
    let max = 0;
    let res = [];
    for (let key in obj) {
    if (obj[key] >= max) {
    if (max !== obj[key]) {
    res = [];
    }
    max = obj[key];
    res.push(key);
    }
    }
    return res;

    应该可以
    anson2017
        58
    anson2017  
       2020-07-10 10:59:34 +08:00
    最简单易懂的话 3 楼
    最优是 43 楼吧
    woodensail
        59
    woodensail  
       2020-07-10 11:05:17 +08:00
    为什么不试试神奇的 lodash 呢

    _.map(_.maxBy(_.toPairs(_.groupBy(_.toPairs(params),_.last)),x=>x[0]|0)[1],_.first)
    shyling
        60
    shyling  
       2020-07-10 11:17:41 +08:00
    [Object.entries(a).sort(([a, b], [c,d]) => d - b)[0][0]]

    不知道啥叫优雅。。。反正直接排序肯定容易读=-=
    purensong
        61
    purensong  
       2020-07-10 11:18:15 +08:00
    43 楼的确实最优了
    wanguorui123
        62
    wanguorui123  
       2020-07-10 13:33:35 +08:00 via iPhone
    改进版:
    var maxKeys = params => Object.entries(params).sort((a,b)=>a[1] < b[1] ? 1 : (a[1] > b[1] ? -1 : 0)).filter((e,i,arr)=>arr[0][1] === e[1]).flatMap(e=>e[0]);
    buhi
        63
    buhi  
       2020-07-10 13:44:21 +08:00
    就这个还要讨论这么长一串 搞不懂
    Zenyk
        64
    Zenyk  
       2020-07-10 16:40:03 +08:00
    建议说 43 最优的先去看看什么叫基数排序 再看看这个排序的适用场景
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1037 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:04 · PVG 06:04 · LAX 14:04 · JFK 17:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.