多级计数器迭代

时间:2017-11-27 17:05:36

标签: algorithm

我坚持按如下方式创建算法。我知道这不应该太难,但我根本无法理解它,也找不到这种模式的正确描述。

基本上我需要一个多级计数器,当数据库中存在组合时,通过从右侧递增来尝试下一个值。

1 1 1 - Start position. Does this exist in database? YES -> Extract this and go to next
1 1 2 - Does this exist in database? YES -> Extract this and go to next
1 1 3 - Does this exist in database? YES -> Extract this and go to next
1 1 4 - Does this exist in database? NO -> Reset level 1, move to level 2
1 2 1 - Does this exist in database? YES -> Extract this and go to next
1 2 2 - Does this exist in database? NO -> Reset level 2 and 1, move to level 3
2 1 1 - Does this exist in database? YES -> Extract this and go to next
2 1 2 - Does this exist in database? YES -> Extract this and go to next
2 1 3 - Does this exist in database? NO -> Reset level 1 and increment level 2
2 2 1 - Does this exist in database? YES -> Extract this and go to next
2 2 2 - Does this exist in database? YES -> Extract this and go to next
2 2 3 - Does this exist in database? YES -> Extract this and go to next
2 3 1 - Does this exist in database? NO -> Extract this and go to next
3 1 1 - Does this exist in database? NO -> Extract this and go to next
3 2 1 - Does this exist in database? NO -> End, as all increments tried

但可能会超过三个级别。

实际上,每个值(如1,2等)实际上是$ value1,$ value2等,其中包含与XML文档匹配的运行时字符串。因此,不仅仅是拉出数据库中已有的每种组合。

1 个答案:

答案 0 :(得分:0)

假设,DB密钥的长度是预先知道的,这是实现它的一种方式。我正在使用TypeScript,但类似的代码可以用您最喜欢的语言编写。

首先,为方便起见,我声明了一些类型定义。

export type Digits = number[];
export type DbRecord = number;

然后我初始化fakeDb对象作为模拟数据源。我写的函数将对这个对象起作用。此对象的键表示数据库记录的键(类型为string)。值是简单的数字(故意顺序);它们代表数据库记录本身。

export const fakeDb: { [ dbRecordKey: string ]: DbRecord } = {
  '111': 1,
  '112': 2,
  '113': 3,
  '211': 4,
  '212': 5,
  '221': 6,
  '311': 7,
};

接下来,您可以看到有趣的部分,这是使用counterDigits“数字”数组来增加的函数,具体取决于记录是否存在。

认为这是生产就绪代码! A)有不必要的console.log()调用仅用于演示目的。 B)最好不要将大量DbRecords从数据库读入内存,而是使用yield/return或某种缓冲区或流。

export function readDbRecordsViaCounter(): DbRecord[] {
  const foundDbRecords: DbRecord[] = [];

  const counterDigits: Digits = [1, 1, 1];
  let currentDigitIndex = counterDigits.length - 1;

  do {
    console.log(`-------`);

    if (recordExistsFor(counterDigits)) {
      foundDbRecords.push(extract(counterDigits));

      currentDigitIndex = counterDigits.length - 1;
      counterDigits[currentDigitIndex] += 1;
    } else {
      currentDigitIndex--;
      for (let priorDigitIndex = currentDigitIndex + 1; priorDigitIndex < counterDigits.length; priorDigitIndex++) {
        counterDigits[priorDigitIndex] = 1;
      }
      if (currentDigitIndex < 0) {
        console.log(`------- (no more records expected -- ran out of counter's range)`);
        return foundDbRecords;
      }
      counterDigits[currentDigitIndex] += 1;
    }

    console.log(`next key to try: ${ getKey(counterDigits) }`);

  } while (true);
}

其余的是一些“帮助”函数,用于从数字数组构造字符串键,并访问虚假数据库。

export function recordExistsFor(digits: Digits): boolean {
  const keyToSearch = getKey(digits);
  const result = Object.getOwnPropertyNames(fakeDb).some(key => key === keyToSearch);
  console.log(`key=${ keyToSearch } => recordExists=${ result }`);
  return result;
}

export function extract(digits: Digits): DbRecord {
  const keyToSearch = getKey(digits);
  const result = fakeDb[keyToSearch];
  console.log(`key=${ keyToSearch } => extractedValue=${ result }`);
  return result;
}

export function getKey(digits: Digits): string {
  return digits.join('');
}

现在,如果你运行这样的函数:

const dbRecords = readDbRecordsViaCounter();
console.log(`\n\nDb Record List: ${ dbRecords }`);

你应该看到以下输出,它告诉你迭代步骤;并在最后报告最终结果。

-------
key=111 => recordExists=true
key=111 => extractedValue=1
next key to try: 112
-------
key=112 => recordExists=true
key=112 => extractedValue=2
next key to try: 113
-------
key=113 => recordExists=true
key=113 => extractedValue=3
next key to try: 114
-------
key=114 => recordExists=false
next key to try: 121
-------
key=121 => recordExists=false
next key to try: 211
-------
key=211 => recordExists=true
key=211 => extractedValue=4
next key to try: 212
-------
key=212 => recordExists=true
key=212 => extractedValue=5
next key to try: 213
-------
key=213 => recordExists=false
next key to try: 221
-------
key=221 => recordExists=true
key=221 => extractedValue=6
next key to try: 222
-------
key=222 => recordExists=false
next key to try: 231
-------
key=231 => recordExists=false
next key to try: 311
-------
key=311 => recordExists=true
key=311 => extractedValue=7
next key to try: 312
-------
key=312 => recordExists=false
next key to try: 321
-------
key=321 => recordExists=false
next key to try: 411
-------
key=411 => recordExists=false
------- (no more records expected -- ran out of counter's range)


Db Record List: 1,2,3,4,5,6,7

强烈建议您阅读代码。如果您希望我描述方法或任何具体细节 - 请告诉我。希望,它有所帮助。