【问题标题】:How to validate values in an object array which have duplicate IDs?如何验证具有重复 ID 的对象数组中的值?
【发布时间】:2021-07-14 21:41:36
【问题描述】:

我有一个如下所示的对象数组:

[
    {
        "id":1,
        "type":"Greater than",
        "value":"5"
    },
    {
        "id":1,
        "type":"Less than",
        "value":"29"
    },
    {
        "id":2,
        "type":"Less than",
        "value":"40"
    },
    {
        "id":3,
        "type":"Greater than",
        "value":"50"
    },
    {
        "id":3,
        "type":"Less than",
        "value":"10"
    },
    {
        "id":4,
        "type":"name",
        "value":"Anna"
    }
]

如果每个 ID 的所有大于/小于都是正确的,我想做一些验证并返回 true。

例如,上面应该返回 false,因为 ID 3 的大于值大于小于值(即使 ID 1 是正确的)。

并非所有 ID 都会同时具有大于和小于(参见 ID 2 和 ID 4)

我一直在尝试不同的方法,但似乎找不到解决方案。

【问题讨论】:

  • 嗨!请参阅 minimal reproducible exampleHow to Ask,因为“我一直在尝试不同的方法,但似乎找不到解决方案”,您可以向我们展示您的尝试,以便我们提供帮助。
  • 我尝试过使用 Array.find 但问题是获取所有匹配的 ID,然后检查它们的范围值。并非所有 ID 都有一对@Wyck
  • 这会让一些人抽搐,因为id 通常是一个独特的字段。如果它是某个else 的 id,比如相关字段的 id,那么可以将其称为 key 或其他名称,所以我们知道它不应该是唯一的。即便如此,值得一提的是这是一个多映射(其中每个键可以有多个值)。
  • 你有三个问题1)在数组中定位适用的对象(为此使用Array.filter),2)测试是否所有过滤条件都适用(Array.every在过滤结果上)和3)使具有属性"type":"Greater than", "value":"5" 的对象引用执行检查(input) => input > 5 的函数并将其应用于输入。那么这三个中的哪一个是您的实际问题?
  • 应该如何验证{ "id":4, "type":"name", "value":"Anna" }

标签: javascript node.js arrays object


【解决方案1】:

数组方法every()在这里会派上用场。

在下面的示例中,我还添加了对“等于”属性的支持,并且我检查了单个数组中包含的所有对象并确保它们都是有效的,忽略任何字符串类型,例如 type: "name", value: "Anna"

检查一下:

const data1 = [
  { id: 1, type: "Greater than", value: "5" },
  { id: 1, type: "Less than", value: "29" },
  { id: 2, type: "Less than", value: "40" },
];

const data2 = [
  { id: 3, type: "Greater than", value: "1" },
  { id: 3, type: "Equal to", value: "3" },
  { id: 4, type: "name", value: "Anna" }
];

const validate = data => data.every(({ id: a, value: b, type: t }) => !["Greater than", "Less than", "Equal to"].includes(t) || ((b = +b), ((t === "Greater than" && (a > b)) || (t === "Less than" && (a < b)) || (t === "Equal to" && (a === b)))));

console.log(validate(data1));
console.log(validate(data2));

如果您不介意字符串和数字之间的某种类型强制,我们可以剪掉整个 (b = +b) 部分并使用双等于 == 进行最后一个“等于”比较,从而使代码相当短。无论哪种方式,我们都将字符串转换为数字,如果我们在比较之前或比较时这样做,似乎不会产生很大的性能差异:

const data1 = [
  { id: 1, type: "Greater than", value: "5" },
  { id: 1, type: "Less than", value: "29" },
  { id: 2, type: "Less than", value: "40" },
];

const data2 = [
  { id: 3, type: "Greater than", value: "1" },
  { id: 3, type: "Equal to", value: "3" },
  { id: 4, type: "name", value: "Anna" }
];

const validate = data => data.every(({ id: a, value: b, type: t }) => !["Greater than", "Less than", "Equal to"].includes(t) || ((t === "Greater than" && (a > b)) || (t === "Less than" && (a < b)) || (t === "Equal to" && (a == b))));

console.log(validate(data1));
console.log(validate(data2));

【讨论】:

  • @user14374853 我已经更新了我的解决方案以使用对象解构和重命名来简化整体逻辑。我们可以只评估a &gt; b,而不是评估x.id &gt; +x.value
  • Neither of the two seems to correctly validate the objects。你从来没有真正检查对象与任何其他对象,只是针对它本身。而且我不确定您为什么要将 ID 与值进行比较。
  • @VLAZ 是的,从问题来看,我相信这正是所要求的。在大多数情况下,每个对象都被评估以查看其id 是否大于或小于其value。请再看一下这个问题,如果我误解了这里的问题,请告诉我,但其他答案似乎也是如此。
  • 不,不是。 ID 只是将规则链接在一起。 OP 清楚地说“上面应该返回 false,因为 ID 3 的大于值大于小于值(即使 ID 1 是正确的)”因此它的 ID 3 是问题,因为边界冲突.并且直接说明 ID 1 是正确的。我看不出 { "id":1, "type":"Greater than", "value":"5" } 如何符合您的逻辑 - 1 显然 大于 5
  • @VLAZ 正确,这就是 data1 返回 false 的原因。整篇文章都是关于验证的。 false 在这里是一个完全可以接受的返回值。
【解决方案2】:

const ids = [
  {
    "id": 1,
    "type": "Greater than",
    "value": "5"
  },
  {
    "id": 1,
    "type": "Less than",
    "value": "29"
  },
  {
    "id": 2,
    "type": "Less than",
    "value": "40"
  },
  {
    "id": 3,
    "type": "Greater than",
    "value": "50"
  },
  {
    "id": 3,
    "type": "Less than",
    "value": "10"
  },
  {
    "id": 4,
    "type": "name",
    "value": "Anna"
  }
]

function check(array) {
  const min = new Map() // Greater than [1->5, 3->50]
  const max = new Map() //    Less than [1->29,3->10]
  for (let { id, type, value } of array) {
    switch (type) {
      case 'Less than':
        //                             > or >=
        if (min.has(id) && min.get(id) > +value) {
          return false
        }
        max.set(id, +value)
        break
      case 'Greater than':
        if (max.has(id) && max.get(id) < +value) {
          return false
        }
        min.set(id, +value)
        break
    }
  }
  return true
}

console.log(
  check(ids)
)

【讨论】:

    【解决方案3】:

    const isValidRange = ([start, end]) =>
      start <= end
    
    function check(arr) {
      const map = new Map();
      
      for (const item of arr) {
        const [start, end] = map.get(item.id) ?? [-Infinity, Infinity];
        
        const value = Number(item.value);
        
        let newRange;
        switch (item.type) {
          case "Greater than":
            newRange = [Math.max(start, value), end];
            break;
          case "Less than":
            newRange = [start, Math.min(value, end)];
            break;
        }
        
        if (!isValidRange(newRange))
          return false;
    
        map.set(item.id, newRange);
      }
      
      return true;
    }
    
    
    const invalid = [ 
      { "id": 1, "type": "Greater than", "value": "5"  }, 
      { "id": 1, "type": "Less than"   , "value": "29" }, 
      { "id": 2, "type": "Less than"   , "value": "40" }, 
      { "id": 3, "type": "Greater than", "value": "50" }, 
      { "id": 3, "type": "Less than"   , "value": "10" } 
    ]
    
    const valid = [ 
      { "id": 1, "type": "Greater than", "value": "5"  }, 
      { "id": 1, "type": "Less than"   , "value": "29" }, 
      { "id": 2, "type": "Less than"   , "value": "40" }, 
      { "id": 3, "type": "Greater than", "value": "50" }, 
      { "id": 3, "type": "Greater than", "value": "51" }, 
      { "id": 3, "type": "Greater than", "value": "25" }, 
      { "id": 3, "type": "Greater than", "value": "52" }, 
    ]
    
    console.log(check(invalid));
    console.log(check(valid));
    1. 将对象转换为表示范围(一对开始和结束值):
      • { "type": "Greater than", "value": "5" } 转换为范围 [5, Infinity]`
      • { "type": "Less than", "value": "29" } 转换为范围 [-Infinity, 29]
    2. 对于具有相同id 的项目,通过选取最高的起始值和最低的结束值来组合范围。以上两者将结合起来创建[5, 29]
    3. 每次将一个范围与另一个组合时,检查新范围是否有效。将[50, Infinity][-Infinity, 10] 结合起来会产生[50, 10],这是错误的。
    4. 如果任何范围无效,则返回false
    5. 如果所有范围都有效,则返回true

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 2017-06-04
      • 2013-10-22
      • 1970-01-01
      相关资源
      最近更新 更多