如何从原子单词形状生成所有可能的单词?

Posted

技术标签:

【中文标题】如何从原子单词形状生成所有可能的单词?【英文标题】:How to generate all possible words from atomic word shapes? 【发布时间】:2021-09-16 01:43:25 【问题描述】:

我正在处理这段代码:

const vowels = ['i', 'a', 'u', 'e', 'E', 'U', 'I', 'o', 'A', 'O', 'o#', 'u#', 'e#', 'i#', 'a#']
const consonants = ['m', 'n', 'q', 'g', 'd', 'b', 'p', 't', 'k', 'h', 'l', 'w', 'f', 's', 'C', 'z', 'v', 'y', 'x', 'r', 'c', 'j', 'Q', 'S', 'Z', '\'']
const tones = ['', '+', '-']
const shapes = [
  'ccvt1vt2',
  'cvt1vt2',
  'cvt',
  'ccvt',
  'c!vt',
]

const words = 

shapes.forEach(shape => 
  words[shape] = generate(shape)
)

function generate(shape) 
  const sets = 
    v: vowels,
    c: consonants,
    t: tones
  

  const selectors = 
  const nodes = []
  shape.replace(/(\w)(\d)?/g, (_, $1, $2 = '') => 
    selectors[`$$1$$2`] = sets[$1]
    nodes.push(`$$1$$2`)
    return _
  )

  // getting lost here
  nodes.forEach(node => 
    
  )


function randomBetween(min, max) 
  return Math.floor(Math.random() * (max - min + 1)) + min


console.log(words)

shapes 数组有如下内容:ccvt1vt2,其中c 表示辅音,v 表示元音,t 表示音调(来自上述 3 组)。类型旁边的数字只是使我们有不相关的值,而像 cc 这样的相同键表示相同的辅音两次,而 c1c2 表示两个不同的辅音。

目标是生成shape 的所有可能组合。我们该怎么做?

对于这个形状cvt,我们会开始看到这个结果:

mi
me
ma
mo
mu
...
mi+
me+
ma+
...
ni
ne
na
no
nu
...

我已经尝试过的是:

function cartesian() 
  var arr = [].slice.call(arguments),
      intLength = arr.length,
      arrHelper = [1],
      arrToReturn = [];

  for (var i = arr.length - 1; i >= 0; i--) 
      arrHelper.unshift(arrHelper[0] * arr[i].length);
  

  for (var i = 0, l = arrHelper[0]; i < l; i++) 
      arrToReturn.push([]);
      for (var j = 0; j < intLength; j++) 
          arrToReturn[i].push(arr[j][(i / arrHelper[j + 1] | 0) % arr[j].length]);
      
  

  return arrToReturn;


const vowels = [
  'i',
  'a',
  'u',
  'e',
  'E',
  'U',
  'I',
  'o',
  'A',
  'O',
  'o#',
  'u#',
  'e#',
  'i#',
  'a#',
]

const consonants = [
  'm',
  'n',
  'q',
  'g',
  'd',
  'b',
  'p',
  't',
  'k',
  'h',
  'l',
  'w',
  'f',
  's',
  'C',
  'z',
  'v',
  'y',
  'x',
  'r',
  'c',
  'j',
  'Q',
  'S',
  'Z',
  '\'',
]

const tones = [
  '',
  '+',
  '-',
]

const nasals = [
  '',
  '~',
]

const pharyngeals = [
  '',
  '~',
]

const ejectives = [
  '',
  '!',
]

const implosives = [
  '',
  '?',
]

const shapes = [
  'ccvt1vt2',
  'cvt1vt2',
  'cvt',
  'ccvt',
  'c!vt',
]

const words = 

shapes.forEach(shape => 
  words[shape] = generate(shape)
)

function generate(shape) 
  const sets = 
    v: vowels,
    c: consonants,
    t: tones,
    n: nasals,
    p: pharyngeals
  

  const selectors = 
  const string = []
  shape.replace(/(\w)(\d)?/g, (_, $1, $2 = '') => 
    selectors[`$$1$$2`] = sets[$1]
    string.push(`$$1$$2`)
    return _
  )

  const keys = Object.keys(selectors)
  const values = keys.map(selector => selectors[selector])
  const combinations = cartesian(...values)
    .map(nodes => 
      const map = 
      nodes.forEach((node, i) => map[keys[i]] = node)
      return map
    )

  const result = []
  combinations.forEach(combination => 
    const out = shape.replace(/(\w+)/g, (_, $1) => 
      return combination[$1]
    )
    result.push(out)
  )

  return result


function randomBetween(min, max) 
  return Math.floor(Math.random() * (max - min + 1)) + min

这里是生成随机值的版本,内存中存储的值太多了。

const vowels = [
  'i',
  'a',
  'u',
  'e',
  'E',
  'U',
  'I',
  'o',
  'A',
  'O',
  'o#',
  'u#',
  'e#',
  'i#',
  'a#',
]

const consonants = [
  'm',
  'n',
  'q',
  'g',
  'd',
  'b',
  'p',
  't',
  'k',
  'h',
  'l',
  'w',
  'f',
  's',
  'C',
  'z',
  'v',
  'y',
  'x',
  'r',
  'c',
  'j',
  'Q',
  'S',
  'Z',
  '\'',
]

const tones = [
  '',
  '+',
  '-',
]

const nasals = [
  '',
  '~',
]

const focusings = [
  '',
  '~',
  '=',
  'Y',
  'w',
  'h',
]

const explosivities = [
  '',
  '!',
  '?',
]

const shapes = [
  'cfevtn',
  'cfevt1nvt2n',
  'cfecfevtn',
  'cfecfevt1nvt2n',
  'c1f1e1c2f2e2vtn',
  'cfev1tnv2tn',
  'cfecfev1tnv2tn',
]

function generate() 
  const sets = 
    v: vowels,
    c: consonants,
    t: tones,
    n: nasals,
    f: focusings,
    e: explosivities
  

  const shape = shapes[randomBetween(0, shapes.length - 1)]

  const selectors = 
  const string = []
  shape.replace(/(\w)(\d)?/g, (_, $1, $2 = '') => 
    selectors[`$$1$$2`] = sets[$1]
    string.push(`$$1$$2`)
    return _
  )

  const values = 
  Object.keys(selectors).forEach(selector => 
    const set = selectors[selector]
    const idx = randomBetween(0, set.length - 1)
    values[selector] = set[idx]
  )

  const result = string.map(selector => values[selector]).join('')

  return result


function randomBetween(min, max) 
  return Math.floor(Math.random() * (max - min + 1)) + min


console.log(generate())
console.log(generate())
console.log(generate())
console.log(generate())

【问题讨论】:

试图使其更具可读性 !是什么意思? 到目前为止,您尝试了哪些方法来自行解决此问题?它有什么问题? @Andreas 我添加了我的尝试,我猜对了吗? 如果您有工作代码,但正在寻找更简单、更清洁、更高效、更优雅等,那么Code Review 更合适。另外:“这是一个生成随机值的版本”:我不明白为什么会出现在您的问题中,因为您明确 要求 生成 all 可能性。它使问题变得混乱。你是在随机生成之后还是在完全生成之后? 【参考方案1】:

这不是您问题的确切答案——因此我向 Stack Overflow 纯粹主义者道歉——但它可能对您有所帮助,具体取决于您的目标。所以我想无论如何我都会分享。 :)

Typescript 的template literal types 可以帮助我们。我们首先定义一些字符串联合类型:

type Vowel = 'i' | 'a' | 'u' | 'e' | 'E' | 'U' | 'I' | 'o' | 'A' | 'O' | 'o#' | 'u#' | 'e#' | 'i#' | 'a#'
type Consonant = 'm' | 'n' | 'q' | 'g' | 'd' | 'b' | 'p' | 't' | 'k' | 'h' | 'l' | 'w' | 'f' | 's' | 'C' | 'z' | 'v' | 'y' | 'x' | 'r' | 'c' | 'j' | 'Q' | 'S' | 'Z' | '\''
type Tone = '' | '+' | '-'

这让我们可以使用模板文字类型来为给定的形状/模式创建每个枚举;例如,对于'cvt'

type ShapeString = `$Consonant$Vowel$Tone`

这反过来又允许我们定义一个mapped type,它代表我们的ShapeString的字典:

type EveryCombinationOfShapeString =  [K in ShapeString]: K

现在您的 IDE 应该能够帮助枚举该类型的对象:

const Dictionary: EveryCombinationOfShapeString = 
  // ...
  "Ce-": 'Ce-',
  "Ci#": 'Ci#',
  "Ci#+": 'Ci#+',
  "Ci#-": 'Ci#-',
  // ...

^ 我不会在这里发布整个内容,因为它已经有 1000 多行,只有 3 个字符,但我可以确认 WebStorm 能够在大约 30 秒左右为我实现这个对象的所有成员。

我知道这忽略了您问题的c1c1 方面,并且还引入了一种新语言,但我希望它仍然会有所帮助。也许您可以在该对象上使用Object.values 并进行一些额外的过滤/映射。

(为清晰起见进行编辑、重命名、文档链接等)

【讨论】:

是的,我承认这一点。但是,它确实会生成一个 js 对象,可以帮助提问者更接近问题的解决方案:) "也许您可以在该对象上使用 Object.values" 整个问题是如何生成所有可能的值。我不认为“手动生成所有排列然后获取它们”是一个非常好的方法。 不是手工制作的。一个称职的 ide 可以实现给定接口的成员;这就是重点

以上是关于如何从原子单词形状生成所有可能的单词?的主要内容,如果未能解决你的问题,请参考以下文章

从给定的单词列表中生成具有“N”长度的所有可能组合(寻找不重复)

如何从特征向量或单词生成句子?

什么工具能将给定的几个单词的所有组合生成指定位数的字典?跑hashcat用

NLP语言模型

生成所有变体的算法

用NLTK/Python生成一串N个随机英文单词