首页 > 解决方案 > 按最长公共起始子字符串对数组元素进行分组

问题描述

如何按最长的公共字符串对公共子字符串进行分组。它指的是按最长公共起始子字符串分组字符串

Alex Shevchenko 提供了一段非常好的代码,但在某些情况下它不能正常工作。添加到var dataapple iphone 65使数据看起来像:

var data = ['apple iphone 65', 'apple ipad mini 32gb', 'apple ipad mini 64gb', 'apple ipad air 64gb', 'apple ipad air 32gb', 'panasonic gh4', 'samsung s2 galaxy', 'samsung s2 galaxy red', 'samsung s3 galaxy'];

下面是预期的结果。

result = {
 "apple": [
     "apple iphone 65"
 ],
 "apple ipad mini": [
     "apple ipad mini 32gb",
     "apple ipad mini 64gb"
 ], ...;

下面是我实际得到的。

result = {
 "apple": [
     "apple iphone 65",
     "apple ipad mini 32gb"
 ],
 "apple ipad mini": [
     "apple ipad mini 64gb"
 ],
 "apple ipad air": [
     "apple ipad air 64gb",
     "apple ipad air 32gb"
 ],
 "panasonic gh4": [
     "panasonic gh4"
 ],
 "samsung s2 galaxy": [
     "samsung s2 galaxy",
     "samsung s2 galaxy red"
 ],
 "samsung s3 galaxy": [
     "samsung s3 galaxy"
 ]
};

我无法弄清楚我的代码中的错误在哪里。

标签: javascript

解决方案


我不确定我的解决方案的效率如何,尤其是当/当数据集大小增加时,但我认为它非常接近您正在寻找的内容。

var data = ['apple iphone 65gb', 'apple ipad mini 32gb', 'apple ipad mini 64gb', 'apple ipad air 64gb', 'apple ipad air 32gb', 'panasonic gh4', 'samsung s2 galaxy', 'samsung s2 galaxy red', 'samsung s3 galaxy']

let i = 0
let obj = {}

function checkArrays(arrA, arrB) {
  let index
  for (let i = 0; i < arrA.length; i++) {
    if (arrA[i] !== arrB[i]) return index = i
  }
  return index;
}

const refineArr = (data) => {
  arr = []
  for (let i = 0; i < data.length; i++) {
    let one = data[i].split("")
    let two = data[i + 1] ? data[i + 1].split("") : data[i + 1]
    if (two) {
      let x = checkArrays(one, two)

      var index1, index2

      one.forEach((y, e) => {
        if (y === " " && e >= x) {
          return index1 = e
        }
      })

      if (!arr.includes(one.slice(0, index1).join("").trim()) &&
        !arr.includes(one.slice(0, index2).join("").trim())) {
        arr.push(one.slice(0, index1).join("").trim())
      }

      two.forEach((y, i) => {
        if (y === " " && i >= x) {
          return index2 = i
        }
      })

      if (!arr.includes(two.slice(0, index2).join("").trim()) &&
        !arr.includes(two.slice(0, index1).join("").trim())) {
        arr.push(two.slice(0, index2).join("").trim())
      }
    }
  }
  var newArr = [...new Set(arr)]
  generateObject(newArr)
}

const generateObject = (arr) => {
  for (let i = 0; i < arr.length; i++) {
    if (!obj[arr[i]]) {
      obj[arr[i]] = data.filter((x) => {
        return x.includes(arr[i])
      })
    }
  }
  console.log(obj)
}

refineArr(data)
.as-console-wrapper { top: 0; max-height: 100% !important; }

首先,我尝试改进原始数组以仅包含将要包含的键。当我遍历时,data我在每个索引处拆分字符串(以及下一个索引,只要i+1定义了项目)。然后我将这两个数组传递到checkArrays我比较每个字符的位置,然后返回它们不再相同的索引。

示例:apple ipad mini ...作为数组是

["a", "p", "p", "l", "e", " ", "i", "p", "a", "d", " ", "m", "i", "n", "i", ...]

并且apple ipad air...作为一个数组是

["a", "p", "p", "l", "e", " ", "i", "p", "a", "d", " ", "a", "i", "r",...]

他们不再相似的指数是11

然后我需要找到它们不同的索引(对于两者),加上下一个空格,因为我想确保我将数组切片为一个完整的单词。所以我寻找的是一个空格并且索引大于差异索引的元素。

我对两个数组都这样做,因为索引会不同。

因为["a", "p", "p", "l", "e", " ", "i", "p", "a", "d", " ", "m", "i", "n", "i", ...]它是15

因为["a", "p", "p", "l", "e", " ", "i", "p", "a", "d", " ", "a", "i", "r", ...]它是14

有一种情况,我最终apple ipad m会被推到arr后面,apple ipad mini但那是因为我需要测试每个数组的两个索引(因为在第一个循环 apple ipad mini ...中是第二个单词,但在第二个循环中是第一个单词)。我用以下几行来弥补这一点:

  if (!arr.includes(one.slice(0, index1).join("").trim()) 
      && !arr.includes(one.slice(0, index2).join("").trim())){
    arr.push(one.slice(0, index1).join("").trim())
  }

 if (!arr.includes(two.slice(0, index2).join("").trim())
     && !arr.includes(two.slice(0, index1).join("").trim())){
    arr.push(two.slice(0, index2).join("").trim())
  }

完成后,我返回了一个新数组,使用var newArr = [... new Set(arr)]以确保省略任何重复的值。在这一点上,你最终会得到一个像["apple iphone", "apple ipad mini", "apple ipad air", "panasonic", "samsung s2", "samsung s3"]. 这些将是我们对象中的键。

最后,generateObject循环遍历新数组并实质上将过滤后的项目集合的键值分配给include键。因此,对于密钥apple ipad mini,您将获得过滤后的集合["apple ipad mini 32gb", "apple ipad mini 64gb"]

同样,我认为这个解决方案需要改进以提高效率,但我认为它可以帮助你至少在逻辑上开始。


推荐阅读