【问题标题】:Extract element from array depending on elements of array根据数组的元素从数组中提取元素
【发布时间】:2018-07-08 23:43:34
【问题描述】:

我有一个可以匹配此数据结构的任意组合的结果集:

[ ["1st", "FELONY"], ["2nd", "FELONY"],  ["3nd", "FELONY"], ["1st", "MISDEMEANOR"], ["2nd", "MISDEMEANOR"], ["3rd", "MISDEMEANOR"]]  

所以它可能是这样的:

[  ["2nd", "FELONY"], ["2nd", "MISDEMEANOR"], ["1st", "MISDEMEANOR"]]           

或者这个:

[ ["1st", "MISDEMEANOR"], ["2nd", "MISDEMEANOR"]]    

或其他元素的组合和顺序。

如果数组有一个 FELONY 的子数组,那么我想忽略 MISDEMEANOR 元素,如果存在则只获取“1st”,否则为“2nd”,否则为“3rd”。 现在,如果数组不包含 FELONY 元素,那么我想拉“第一个”MISDEMEANOR 元素(如果存在),否则为“第 2 个”,否则为“第 3 个”。

我的解决方案:

var arr = [ ["1st", "FELONY"], ["3nd", "FELONY"], ["2nd", "FELONY"], ["2nd", "MISDEMEANOR"], ["3rd", "MISDEMEANOR"], ["1st", "MISDEMEANOR"]];
for(var i = 0, found = [], fel1 = false, fel2 = false, fel3 = false, mis1 = false, mis2 = false, mis3 = false; i < arr.length; i++) {
   if(arr[i][0] == "1st" && arr[i][1] == "FELONY"){
       found = arr[i];
       fel1 = true;
   } else if (arr[i][0] == "2nd" && arr[i][1] == "FELONY" && !fel1){
       found = arr[i];
       fel2 = true;
   } else if (arr[i][0] == "3rd" && arr[i][1] == "FELONY" && !fel1 && !fel2){
       found = arr[i];
       fel3 = true;
   } else if (arr[i][0] == "1st" && arr[i][1] == "MISDEMEANOR" && !fel1 && !fel2 && !fel3){
       found = arr[i];
       mis1 = true;
   } else if (arr[i][0] == "2st" && arr[i][1] == "MISDEMEANOR" && !fel1 && !fel2 && !fel3 && !mis1){
       found = arr[i];
       mis2 = true;
   } else if (arr[i][0] == "3st" && arr[i][1] == "MISDEMEANOR" && !fel1 && !fel2 && !fel3 && !mis1){
       found = arr[i];
       mis3 = true;
   }
}


if( match && (match[2] == "FELONY" || match[2] == "MISDEMEANOR") && (found[2] != "FELONY" && found[1] != "1st") ) {
            found = [ match[1], match[2], match[3], match[4] ]
            console.log("FOUND! " + found[1]);
} else {
            console.log(`could not parse ${chargesList[i]}`);
}

console.log(JSON.stringify(found));

它完成了工作,但有点马虎。有没有更好的方法来使用 EcmaScript 6 功能做到这一点?

【问题讨论】:

    标签: javascript arrays algorithm data-structures ecmascript-6


    【解决方案1】:

    理想情况下,您只想遍历数组一次,并尽可能避免使用 if/else ifs 的巨大字符串。一种方法是使用一个系统,该系统允许您为每个项目制作唯一分数,其中最高分数是您想要的项目。有很多方法可以做到这一点,但一种简单的方法是将数字分配给 felony 和 misdemeanor 以保证它们大于第二维。重罪/轻罪获得第 10 名,第 1、第 2、第 3 名占第 1 名。然后你可以查看你的数组一次并找到最高分:

    let scores = {
      FELONY: 20,
      MISDEMEANOR: 10,
      '1st': 3,
      '2nd': 2,
      '3rd': 1
    }
    
    let arr = [["2nd", "FELONY"],["2nd", "MISDEMEANOR"], ["1st", "MISDEMEANOR"],["1st", "FELONY"]]
    
    let highest = 0, result
    for (item of arr) {
      let score = item.reduce((a, c) => a + scores[c], 0)
      if (score > highest) {
        highest = score
        result = item
      }
    }
    console.log(result)

    这也使得编辑您的偏好或添加不同的类别变得非常容易,而且它不依赖于您的类别的字母排序顺序。

    【讨论】:

      【解决方案2】:

      一个非常简单的版本是:

      function mySort(a) {
        return [...a].sort(([aa, ab], [ba, bb]) => (ab + aa).localeCompare(bb + ba))
      }
      

      然后像这样使用它:

      const [selected] = mySort(arr)
      

      需要注意的几点:

      • 我们需要[...a] 来复制数组,因为sort 会改变它所操作的数组
      • 这仅适用于来自FELONY 的F 位于来自MISDEMEANOR 的M 和您的1st、2nd 和3rd 之前以数字开头
      • 这不是一种高效的方法,但在你的情况下它可能没问题

      如果您确实需要其他字符串进行排序,您可以使用查找表:

      const lookup = {
        FELONY: 1,
        MISDEMEANOR: 2,
        ...
      }
      
      sort(... => (lookup[ab] + lookup[aa]).localeCompare(...))
      

      【讨论】:

        【解决方案3】:

        不确定以下内容是否比您所拥有的更优雅或更好,(留给 JS 专家在这里发表评论)但是我可以提出一些您的建议

        虽然做了以下粗略的假设:-|

        1. 内部数组(子数组)的第一个索引总是以数字开头,例如 1st、2nd 等

          1.1 数字后面的字母是个位数(不大于 9)。

        var sampleArray = [ ["1st", "FELONY"], ["2nd", "FELONY"],  ["3nd", "FELONY"], ["1st", "MISDEMEANOR"], ["2nd", "MISDEMEANOR"], ["3rd", "MISDEMEANOR"]] 
        // var sampleArray = [["2nd", "FELONY"], ["2nd", "MISDEMEANOR"], ["1st", "MISDEMEANOR"]]
        // var sampleArray = [["2nd", "FELONY"], ["2nd", "MISDEMEANOR"], ["1st", "MISDEMEANOR"]]
         
        var reducedArray = sampleArray.reduce((a,b) => a.concat(b))
        
        // step 1 : to just filter felony if any.
        let result = [];
        if(reducedArray.includes("FELONY")) {
        sampleArray.forEach(a => {if(a.includes("FELONY")) {
            result.push(a);
        }})
        }else{
        result = sampleArray;
        }
        
        // step 2: sort and print first
        
        result.sort((a,b) => {
        if(a[0].substring(0) < b[0].substring(0)) {
            return -1;
        } else if(a[0].substring(0) > b[0].substring(0)){
            return 1;
        }
        return 0;
        })
        
        console.log(result[0]); 

        【讨论】:

          【解决方案4】:

          您可以轻松地将结构转换为对象结构。这适用于任何数量的人或病房后的排名。

          const list = [ ["1st", "FELONY"], ["2nd", "FELONY"],  ["3nd", "FELONY"], ["1st", "MISDEMEANOR"], ["3rd", "MISDEMEANOR"]]  
          
          let obj = {}
          list.forEach((item, index) => {
            obj = {
              ...obj,
              [item[1]] : {
                 ...obj[item[1]],
                 [item[0]]: index,
              }
            }
          })
          
          console.log(obj)

          所以你可以看到,对于上面给出的列表,我们的对象看起来像

          {
            "FELONY": {
              "1st": 0,
              "2nd": 1,
              "3nd": 2
            },
            "MISDEMEANOR": {
              "1st": 3,
              "3rd": 4
            }
          }
          

          现在我们可以提取所需的值

          const obj = {
            "FELONY": {
              "1st": 0,
              "2nd": 1,
              "3nd": 2
            },
            "MISDEMEANOR": {
              "1st": 3,
              "3rd": 4
            }
          }
          
          let nameToLookFor = 'FELONY';
          if (!obj[nameToLookFor) {
            nameToLookFor = 'MISDEMEANOR'
          }
          
          const found = 
            obj[nameToLookFor]['1st'] || obj[nameToLookFor]['2nd'] || obj[nameToLookFor]['3rd']);
          
          console.log(found)

          const obj = {
            "FELONY": {
              "1st": 0,
              "2nd": 1,
              "3nd": 2
            },
            "MISDEMEANOR": {
              "1st": 3,
              "3rd": 4
            }
          }
          
          let nameToLookFor = 'FELONY';
          if (!obj[nameToLookFor]) {
            nameToLookFor = 'MISDEMEANOR'
          }
          
          
          const found = 
            obj[nameToLookFor]['1st'] || obj[nameToLookFor]['2nd'] || obj[nameToLookFor]['3rd'];
          
          console.log(found)

          【讨论】:

            【解决方案5】:
            function penaltiesSort(data){
                const   felonies = data.filter(subArr => subArr[1] == "FELONY" ),
                        misdemeanors = data.filter(subArr => subArr[1] == "MISDEMEANOR");
            
                function sorter(arr){
                  const newarr = [];
            
                  for(let i = 0; i < arr.length; i++){
                    newarr[arr[i][0][0] - 1] = arr[i];
                  }
            
                  return newarr[0] || newarr[1] || newarr[2];
                }
            
                return felonies.length > 0 ? sorter(felonies) : sorter(misdemeanors);
            }
            
            • 对于初学者,我建议使用 es6 过滤器数组方法来区分重罪和轻罪,此方法返回一个包含满足条件的元素的数组,在我们的例子中是“FELONY”或“MISDEMEANOR”
            • 我写的下一个东西是一个自定义排序器,它接收一个数组,循环遍历它,并使用我们找到的数字,这将是我们 newarr 中的索引分配,所以如果我们遇到“第一个”,我们会打破它下降到 1 然后我们从中减去 -1 并将其放在 newarr 的 0 索引中。正在发生的事情是,我们正在利用它已经拥有的数字将其放置在其各自的“位置”中。
            • 我们自定义排序器的最后一条语句是返回它遇到的第一个项目,这将取决于我们提供给它的数据,例如 [ ["3rd", "MISDEMEANOR"], ["2nd", " MISDEMEANOR"]] 在位置 0 处没有项目,但在位置 1 处,因此 ||声明非常适合这份工作
            • 最后,三元运算通过检查长度来检查是否有任何重罪,如果有,则返回重罪分类器的结果,否则我们返回轻罪的结果

            【讨论】:

            • For starters a good es6 practice would be to use the filter array - 顺便提一下这个“好的 es6 实践”在哪里?如果您有强烈的感觉,请改用“推荐”一词。
            • 你说得对,这只是我的建议,但它是一种很好的做法,因为它减少了在寻找循环数组以检索某些元素时编写条件的需要通过使用条件语句。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-07-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多