如何根据具有代表性的记录和 属性 特定的生成器函数随机模拟记录数组?

How to randomly simulate an array of records based on a representative record and property-specific generator functions?

给定一条记录的结构,如何随机模拟n条相同结构的记录?

例子

假设我有一个记录数组,例如:

[
    {
        "id": 12345,
        "createdAt": "2021-12-25",
        "data": {
            "age": {"value": 25},
            "height": {"value": 100},
            "weight": {"value": 160},
            "n_of_kids": {"value": 0},
            "fam_status": {"value": "married"},
            "preferred_pet": {"value": "dog"},
            "preferred_color": {"value": "purple"},
            "preferred_movie": {"value": "titanic"}
        }
    },
    {...} // another record
]

我的任务:我想模拟一个n条记录的数组,与上面的结构相同

注意。我特别想找到一个适用于任何给定结构的解决方案。因此,虽然我知道这里给出的结构是次优的(例如,冗余 value 属性 并没有增加太多),但我仍然希望能够解释任何可能的给定结构.


我可以解决这个问题的一种方法是创建一个对象,其 是指定每个值应该是什么的正则表达式。

const structureTemplateRegex = {
  id: "^[0-9]{5}$", // 5-digit number
  createdAt: /^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/, // yyyy-mm-dd
  data: { 
    age: { value: "/^(?:[0-9]|[1-9][0-9]|100)$/" }, // 0-100
    height: { value: "/^(?:1[0-9]|[2-9][0-9]|1[0-9]{2}|2[01][0-9]|220)$/" }, // 10-220
    weight: { value: '/^(?:3[0-9]|[4-9][0-9]|[12][0-9]{2}|300)$/' }, // 30-300
    n_of_kids: { value: '/^(0|[1-9][0-9]?|7)$/' }, // 0-7
    fam_status: { value: '/^(married|single|divorced|widowed)$/' },
    preferred_pet: { value: '/^(dog|cat|hamster|fish|rabbit|zebra)$/' },
    preferred_color: { value: '/^(red|green|yellow|black|orange|blue)$/' },
    preferred_movie: {
      value: '/^(titanic|alien|se7en|batman|goodfellas|argo)$/',
    },
  },
};

嗯,structureTemplateRegex 可能适合验证,但不适合生成数据。所以另一种解决问题的方法是为记录中的每个 属性 编写一个生成器函数。

const generateId = (n = 5) => [...Array(n)].map(_=>Math.random()*10|0).join`` // 
const generateDate = (start = new Date(2018, 8, 9), end = new Date(2021, 12, 15)) => new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString().slice(0,10); // 
const randomInteger = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; // 
const randomElement = (arr) => arr[(Math.random() * arr.length) | 0] // 
const generateFamStatus = () => randomElement(["married", "single", "divorced", "widowed"])
const generatePet = () => randomElement(["dog", "cat", "hamster", "fish", "rabbit", "zebra"])
const generateColor = () => randomElement(["red", "green", "yellow", "black", "orange", "blue"])
const generateMovie = () => randomElement(["titanic", "alien", "se7en", "batman", "goodfellas", "argo"])

// and then
const structureTemplateGenerators = {
    id: generateId(), // 5-digit number
    createdAt: generateDate(), // yyyy-mm-dd
    data: { 
      age: { value: randomInteger(0, 101) }, // 0-100
      height: { value: randomInteger(10, 221) }, // 10-220
      weight: { value: randomInteger(30, 301) }, // 30-300
      n_of_kids: { value: randomInteger(0, 8) }, // 0-7
      fam_status: { value: generateFamStatus() },
      preferred_pet: { value: generatePet() },
      preferred_color: { value: generateColor() },
      preferred_movie: {
        value: generateMovie(),
      },
    },
  };

但我不太确定如何沿着这条路走下去。我有我需要的材料,但没有技术。本质上,我想要的是调用一个函数,该函数将以下参数作为参数:(1) 一个代表性记录的结构,以及 (2) n 要模拟的记录数。该函数将 return 一个长度为 n 的数组,其中包含随机生成的记录。

// pseudocode
generateRecords(structureTemplateGenerators, 5) // but `n` could potentially be 10 or 10000 or 3e7

// would return
const possibleOutput = [
  {
    id: 12045,
    createdAt: '2021-02-21',
    data: {
      age: { value: 15 },
      height: { value: 80 },
      weight: { value: 100 },
      n_of_kids: { value: 1 },
      fam_status: { value: 'widowed' },
      preferred_pet: { value: 'dog' },
      preferred_color: { value: 'purple' },
      preferred_movie: { value: 'se7en' },
    },
  },
  {
    id: 39847,
    createdAt: '2020-12-02',
    data: {
      age: { value: 33 },
      height: { value: 56 },
      weight: { value: 210 },
      n_of_kids: { value: 3 },
      fam_status: { value: 'married' },
      preferred_pet: { value: 'zebra' },
      preferred_color: { value: 'blue' },
      preferred_movie: { value: 'argo' },
    },
  },
  {
    id: 22435,
    createdAt: '2018-10-10',
    data: {
      age: { value: 25 },
      height: { value: 103 },
      weight: { value: 165 },
      n_of_kids: { value: 5 },
      fam_status: { value: 'married' },
      preferred_pet: { value: 'dog' },
      preferred_color: { value: 'green' },
      preferred_movie: { value: 'titanic' },
    },
  },
  {
    id: 61194,
    createdAt: '2019-04-10',
    data: {
      age: { value: 20 },
      height: { value: 90 },
      weight: { value: 100 },
      n_of_kids: { value: 3 },
      fam_status: { value: 'divorced' },
      preferred_pet: { value: 'hamster' },
      preferred_color: { value: 'blue' },
      preferred_movie: { value: 'batman' },
    },
  },
  {
    id: 22231,
    createdAt: '2021-10-01',
    data: {
      age: { value: 77 },
      height: { value: 160 },
      weight: { value: 69 },
      n_of_kids: { value: 1 },
      fam_status: { value: 'divorced' },
      preferred_pet: { value: 'dog' },
      preferred_color: { value: 'red' },
      preferred_movie: { value: 'titanic' },
    },
  },
];

更多上下文

我有一个 JavaScript 应用程序,它接受一组记录并对这些数据进行大量聚合计算。最终,应用程序 return 的输出类似于 JSON。知道输入记录的结构,我想模拟,随机,一个包含n条记录的数组.这样的程序将允许我在 (1) 计算可靠性和 (2) 速度(随着 n 增加)方面测试我的应用程序。

structureTemplateGenerators 应该是 returns 一个新生成的数据结构的函数。现在,它只是创建一个已经设置了值的结构。

const structureTemplateGenerators = () => ({
    id: generateId(), // 5-digit number
    createdAt: generateDate(), // yyyy-mm-dd
    data: { 
      age: { value: randomInteger(0, 101) }, // 0-100
      height: { value: randomInteger(10, 221) }, // 10-220
      weight: { value: randomInteger(30, 301) }, // 30-300
      n_of_kids: { value: randomInteger(0, 8) }, // 0-7
      fam_status: { value: generateFamStatus() },
      preferred_pet: { value: generatePet() },
      preferred_color: { value: generateColor() },
      preferred_movie: {
        value: generateMovie(),
      },
    },
  });

然后您可以创建一个特定长度的数组并通过映射调用该函数,以获取要添加的新随机项。

const output = Array(5).fill(0).map(structureTemplateGenerators)