【问题标题】:Javascript: array difference but occurrencies between parenthesesJavascript:数组差异但括号之间的出现
【发布时间】:2022-10-04 16:04:29
【问题描述】:

假设我们有 2 个数组

a = ['1', '2', '3', '4', '5']
b = ['1', '3', '5']

这2个数组的区别

diff = a.filter(x => !b.includes(x));

所以差异等于['2', '4']

我的问题是我可以

a = ['1', '2', '3(4)', '4', '5'] // (I have 4 occurrencies of "3")
b = ['1', '3', '5'] 
// or 
b = ['1', '3(3)', '5']

我想得到这个数组

diff = ['2', '3(3)', '4'] 
// or 
diff = ['2', '3', '4']

【问题讨论】:

  • ...b.includes(x.split("(")[0]) 在搜索之前丢弃括号内容。如果您想考虑这些计数,它会更加复杂,并且您最好使用查找表对象或集合。
  • @dandavis 不会返回所需的结果。结果如何将3(4) 更改为3(3)
  • @Barmar 不会。亲吻,带有关于更复杂选项的“警告”。
  • 在小范围内,我会编写一个将3(2) 转换为3, 3 的paren 解码器,运行朴素算法,然后编写一个执行反向操作的paren 编码器。
  • 我首先将数组转换为['1', '2', '3', '3', '3', '3', '4', '5'] 之类的东西。然后循环第二个数组,从第一个数组中删除一个匹配元素。然后您可以将结果转换回紧凑形式。

标签: javascript arrays


【解决方案1】:

您的数据格式很尴尬。如果您可以对此做出决定,我建议您改为这样做(对于像 ['1', '2', '3(4)', '4', '5'] 这样的数组):

  • 使用每个元素的出现次数尽可能多的平面数组,例如:

     ['1', '2', '3', '3', '3', '3', '4', '5']
    
  • 使用一个元组数组,每个元素中的第二个值是它的计数,例如:

     [['1',1], ['2',1], ['3',4], ['4',1], ['5',1]]
    
  • 使用类似地图的对象,其值为计数,例如:

     {'1':1, '2':1, '3':4, '4':1, '5':1}
    
  • 使用仅包含计数的数组,其中索引隐含地是键:

     [0, 1, 1, 4, 1, 1]
    

任何这些都会让你的喜欢更容易。


如果这对您来说都不是一个有效的选择,我会为您指出正确的方向来实现一个函数来比较 2 个元素,根据您的规则产生合并的差异值:

function diff(s1,s2) {
  const re = /([0-9]+)(?:(([0-9]+)))?/
  const [,n1,q1] = re.exec(s1)
  const [,n2,q2] = re.exec(s2)
  if (n1!=n2) return  
  const q = Number(q1||1) - Number(q2||1)
  if (q <= 0) return 
  if (q == 1) return n1
  return n1 + `(${q})`
}

console.log(diff("3(4)", "3"   )) // "3(3)"
console.log(diff("3(4)", "3(2)")) // "3(2)"
console.log(diff("3(4)", "3(3)")) // "3"
console.log(diff("3(4)", "3(4)")) // undefined
console.log(diff("3(4)", "3(5)")) // undefined
console.log(diff("3"   , "3"   )) // undefined
console.log(diff("3"   , "3(2)")) // undefined
console.log(diff("3"   , "5"   )) // undefined

您可以从这里开始迭代您的数组并使用合并值生成差异。

【讨论】:

    【解决方案2】:

    我认为诀窍是将每个元素重新定义为可以使用的对象:

    12(3) 将等同于:

    {
      value: 12
      times: 3
    }
    

    或 8

    {
      value: 8
      times: 1
    }
    

    然后您可以创建字典并进行计算。

    尝试这个:

    const a = ['1', '2', '3(4)', '4', '5'] // (I have 4 occurrencies of "3")
    const b = ['1', '3', '5'] 
    
    console.log(diff(a,b))
    
    function diff(arr, minusArr)
    {
      const dict = arr.reduce(
        (dict, current) => {
          const {value, times} = unpack(current)
          dict[value] = (dict[value]?.times ?? 0) + times
          return dict
        }
        ,{}
      )
    
      minusArr.forEach(
        (el)=> {
          const {value, times} = unpack(el)
          if(dict[value] == false) return
    
          dict[value] = 
            dict[value] <= times
              ? 0
              : dict[value] - times
        }
      )
    
      return Object.entries(dict)
        .map(([value, times])=> pack({value, times}))
        .filter(el => el !== '')
    }
    
    function unpack(str)
    {
      return {
        value: parseInt(str).toString(),
        times: parseInt(str.match(/(([0-9]+))/i)?.[1] ?? 1)
      }
    }
    
    function pack({value, times})
    {
      if(times === 1) return value
      if(times === 0) return ''
      return `${value}(${times})`
    }

    【讨论】:

      【解决方案3】:

      您的任务是减去 2 个出现图:每条记录代表某处值出现的次数。

      因此,将此任务拆分为多个步骤。

      1. 将数组转换为更直接的表示形式(映射)
      2. 实现减法逻辑
      3. 将出现映射转换回数组表示。

        const a = ['1', '2', '3(4)', '4', '5']
        const b = ['1', '3(2)', '5']
        
        
        function subtractMaps(a, b) {
          const result = new Map(a)
          for (const [k, bValue] of b.entries()) {
            const aValue = a.get(k)
        
            if (!aValue) continue;
        
            const diff = aValue - bValue;
        
            if (diff > 0) {
              result.set(k, diff);
            } else {
              result.delete(k)
            }
          }
        
          return result;
        }
        
        function mapFromArray(arr) {
          return new Map(arr.map(k => {
            const [key, val = 1] = k.split(/(|)/)
            return [key, Number(val)]
          }))
        }
        
        function mapToArray(map) {
          return [...map.entries()].map(([k, v]) => v > 1 ? `${k}(${v})` : k)
        }
        
        console.log(
          mapToArray(
           subtractMaps(mapFromArray(a), mapFromArray(b))
          )
        )

      【讨论】:

      • 所有.entries() 电话都有原因吗?您使用它们的所有 3 个场景都可以省略。 new Map(a)for (const [k, bValue] of b)[...map] 都可以正常工作。
      • 只是为了明确我的意图,我想遍历条目,而不是说值。它仍然会在引擎盖下被调用,对吧。
      猜你喜欢
      • 2016-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多