【ES6】使用Set和Map进行全组合判断

判断数据集是否为全组合关系

例如下列表格,字段1包含(甲、乙)值,字段2包含(a、b)值,字段3包含(1、2、3)值,每种组合情况都可以在数据集的行记录中找到有且仅有的一条

字段1 字段2 字段3
a 1
a 2
a 3
b 1
b 2
b 3
a 1
a 2
a 3
b 1
b 2
b 3

要求函数输入以下格式数据,输出布尔值。

javascript 复制代码
const inputData = [
	{ "字段1": "甲", "字段2": "a", "字段3": 1 },
	{ "字段1": "甲", "字段2": "a", "字段3": 2 },
	{ "字段1": "甲", "字段2": "a", "字段3": 3 },
	{ "字段1": "甲", "字段2": "b", "字段3": 1 },
	{ "字段1": "甲", "字段2": "b", "字段3": 2 },
	{ "字段1": "甲", "字段2": "b", "字段3": 3 },
	{ "字段1": "乙", "字段2": "a", "字段3": 1 },
	{ "字段1": "乙", "字段2": "a", "字段3": 2 },
	{ "字段1": "乙", "字段2": "a", "字段3": 3 },
	{ "字段1": "乙", "字段2": "b", "字段3": 1 },
	{ "字段1": "乙", "字段2": "b", "字段3": 2 },
	{ "字段1": "乙", "字段2": "b", "字段3": 3 },
]

实现

1.遍历inputData并罗列出每个字段对应的全部可能值:

javascript 复制代码
const inputData = [
  { "字段1": "甲", "字段2": "a", "字段3": 1 },
  { "字段1": "甲", "字段2": "a", "字段3": 2 },
  { "字段1": "甲", "字段2": "a", "字段3": 3 },
  { "字段1": "甲", "字段2": "b", "字段3": 1 },
  { "字段1": "甲", "字段2": "b", "字段3": 2 },
  { "字段1": "甲", "字段2": "b", "字段3": 3 },
  { "字段1": "乙", "字段2": "a", "字段3": 1 },
  { "字段1": "乙", "字段2": "a", "字段3": 2 },
  { "字段1": "乙", "字段2": "a", "字段3": 3 },
  { "字段1": "乙", "字段2": "b", "字段3": 1 },
  { "字段1": "乙", "字段2": "b", "字段3": 2 },
  { "字段1": "乙", "字段2": "b", "字段3": 3 },
]

function isFullCombination(data) {
  if (data.length === 0) {
    return false
  }

  const fieldMap = new Map() // 字段映射对象
  const keys = Object.keys(data[0]) // 获取数据集字段名

  for (const item of data) {
    for (const key of keys) {
      const value = item[key]
      let valueSet = fieldMap.get(key) // 尝试获取Map中字段对应的值集合
      if (!valueSet) {
        valueSet = new Set() // 使用Set实现去重
        fieldMap.set(key, valueSet)
      }
      valueSet.add(value)
    }
  }

  console.log(fieldMap);
}

console.log(isFullCombination(inputData));
javascript 复制代码
Map(3) {
  '字段1' => Set(2) { '甲', '乙' },
  '字段2' => Set(2) { 'a', 'b' },
  '字段3' => Set(3) { 1, 2, 3 }
}

2.那么全组合情况下,inputData数组的长度应为 2*2*3,也就是12,对长度进行判断:

javascript 复制代码
function isFullCombination(data) {
  if (data.length === 0) {
    return false
  }

  const fieldMap = new Map()
  const keys = Object.keys(data[0]) 

  for (const item of data) {
    for (const key of keys) {
      const value = item[key]
      let valueSet = fieldMap.get(key) 
      if (!valueSet) {
        valueSet = new Set() 
        fieldMap.set(key, valueSet)
      }
      valueSet.add(value)
    }
  }
  
  const length = [...fieldMap].reduce((s, [, v]) => (s *= v.size), 1)
  return length === data.length // 对比length
}

3.除了length还需要考虑元素是否重复,如果对inputData进行去重处理,会提高时间复杂度,所以在已有的循环中顺便进行是否重复的判断即可。将所有值拼接为字符串并存储到集合中,对比字符串是否相同。

注意:拼接后的字符存储到集合中,因为需要判断集合中是否已有重复的字符串,所以使用Set存储,因为Set.has时间复杂度为O(1),而Array判断时间复杂度为O(n)。

javascript 复制代码
function isFullCombination(data) {
  if (data.length === 0) {
    return false
  }

  const fieldMap = new Map() 
  const keys = Object.keys(data[0]) 

  const combinationSet = new Set() // 组合情况集合
  for (const item of data) {
    let combination = ""
    for (const key of keys) {
      const value = item[key]
      let valueSet = fieldMap.get(key) 
      if (!valueSet) {
        valueSet = new Set() 
        fieldMap.set(key, valueSet)
      }
      valueSet.add(value)
      combination += value
    }
    if (combinationSet.has(combination)) {
      return false // 如果重复,则说明不是全组合
    }
    combinationSet.add(combination) // 如果不存在,则添加到集合中
  }
  console.log(combinationSet)

  const length = [...fieldMap].reduce((s, [, v]) => (s *= v.size), 1)
  return length === data.length
}

4.但是还存在问题,那就是字段值重复,如下面这个inputData:

javascript 复制代码
const inputData = [
  { a: "-", b: "-" },
  { a: "-", b: "--" },
  { a: "--", b: "-" },
  { a: "--", b: "--" },
]

目前无法判断,需要在存入映射对象时手动将值存为唯一值,这里通过自增的n作为唯一标识,然后使用每个字段对应的唯一标识拼接字符串。

javascript 复制代码
function isFullCombination(data) {
  if (data.length === 0) {
    return false
  }

  const fieldMap = new Map() 
  const keys = Object.keys(data[0]) 
  const combinationSet = new Set()
  const valueMap = new Map() // 记录每个字段的值集合
  let n = 1

  for (const item of data) {
    let combination = ""
    for (const key of keys) {
      const value = item[key]
      let valueSet = fieldMap.get(key)
      if (!valueSet) {
        valueSet = new Set() 
        fieldMap.set(key, valueSet)
      }
      valueSet.add(value)

      let num = valueMap.get(value) // 尝试获取Map中字段对应的值
      if (!num) {
        num = n++
        valueMap.set(value, num) 
      }
      combination += num+''
    }
    console.log(valueMap)

    if (combinationSet.has(combination)) {
      return false 
    }
    combinationSet.add(combination) 
  }

  const length = [...fieldMap].reduce((s, [, v]) => (s *= v.size), 1)
  return length === data.length
}

整体实现代码

javascript 复制代码
const inputData = [
  { 字段1: "甲", 字段2: "a", 字段3: 1 },
  { 字段1: "甲", 字段2: "a", 字段3: 2 },
  { 字段1: "甲", 字段2: "a", 字段3: 3 },
  { 字段1: "甲", 字段2: "b", 字段3: 1 },
  { 字段1: "甲", 字段2: "b", 字段3: 2 },
  { 字段1: "甲", 字段2: "b", 字段3: 3 },
  { 字段1: "乙", 字段2: "a", 字段3: 1 },
  { 字段1: "乙", 字段2: "a", 字段3: 2 },
  { 字段1: "乙", 字段2: "a", 字段3: 3 },
  { 字段1: "乙", 字段2: "b", 字段3: 1 },
  { 字段1: "乙", 字段2: "b", 字段3: 2 },
  { 字段1: "乙", 字段2: "b", 字段3: 3 },
]

// const inputData = [
//   { a: "-", b: "-" },
//   { a: "-", b: "--" },
//   { a: "--", b: "-" },
//   { a: "--", b: "--" },
// ]

function isFullCombination(data) {
  if (data.length === 0) {
    return false
  }

  const fieldMap = new Map() // 字段映射对象
  const keys = Object.keys(data[0]) // 获取数据集字段名
  const combinationSet = new Set() // 组合情况集合
  const valueMap = new Map() // 记录每个字段的值集合
  let n = 1

  for (const item of data) {
    let combination = ""
    for (const key of keys) {
      const value = item[key]
      let valueSet = fieldMap.get(key) // 尝试获取Map中字段对应的值集合
      if (!valueSet) {
        valueSet = new Set() // 使用Set实现去重
        fieldMap.set(key, valueSet)
      }
      valueSet.add(value)

      let num = valueMap.get(value) // 尝试获取Map中字段对应的值
      if (!num) {
        num = n++
        valueMap.set(value, num)
      }
      combination += num + ""
    }
    console.log(combination)

    if (combinationSet.has(combination)) {
      return false // 如果重复,则说明不是全组合
    }
    combinationSet.add(combination) // 如果不存在,则添加到集合中
  }

  const length = [...fieldMap].reduce((s, [, v]) => (s *= v.size), 1)
  return length === data.length
}

console.log(isFullCombination(inputData))
相关推荐
学不会•33 分钟前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS1 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜3 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点3 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow3 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o3 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā4 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年5 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder5 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript