4变量映射到数组

时间:2010-10-05 18:16:27

标签: c math

我需要根据4个变量的值选择一个aray项,如下所示,在C中。

  0  | 1  | 0  | -1 | array[1][0]
  -1 | 0  | 1  | 0  | array[1][1]
  0  | -1 | 0  | 1  | array[1][2]
  1  | 0  | -1 | 0  | array[1][3]

  1  | 0  | 0  | -1 | array[2][0]
  1  | 0  | 0  | 1  | array[2][1]
  -1 | 0  | 0  | 1  | array[2][2]
  -1 | 0  | 0  | -1 | array[2][3]

  0  | 1  | -1 | 0  | array[3][0]
  0  | 1  | 1  | 0  | array[3][1]
  0  | -1 | 1  | 0  | array[3][2]
  0  | -1 | -1 | 0  | array[3][3]

(数组中第二列的顺序并不重要,如果需要可以重新排序。)

虽然可以(并且完全可以接受)将所有可能性都固定在12个链接if中,但我想看看是否有人能想出一个“更清洁”的解决方案。

编辑:澄清:我想要一个函数f(a,b,c,d),其中(例如)f(0, 1, 0, -1)会返回array[1][0]中保存的值。

4 个答案:

答案 0 :(得分:3)

我已经用一种方式来描述这种解决方案,其效率略低于使其更容易解释的方式;更简洁的版本很容易从我在这里展示的内容中得到。

将值-1,0和1映射到0x00,0x01和0x02,并将每个值使用2位存储为8位值,例如,您的数组值对应于以下数字:

array[1][0]: binary value 01100100 = 0x64
array[1][1]: binary value 00011001 = 0x19
array[1][2]: binary value 01000110 = 0x46
array[1][3]: binary value 10010001 = 0x91

为所有255个可能的值创建一个数组,这些值可以保存在8位值中(请注意,不会使用某些条目,即任何两个位都设置为1 - 这就是我提到的低效率。)< / p>

所以,例如

array[0] points to the appropriate array for -1, -1, -1, -1
array[1] points to the appropriate array for -1, -1, -1, 0
array[2] points to the appropriate array for -1, -1, -1, 1
array[3] points nowhere

array[4] points to the appropriate array for -1, -1, 0, -1
array[5] points to the appropriate array for -1, -1, 0, 0
array[6] points to the appropriate array for -1, -1, 0, 1
array[7] points nowhere

(etc, obviously)

然后你只需要一个没有循环的单一查找来获得正确的数组(或者你想要的任何东西)。

在更简洁的解决方案中,该表没有指向任何地方的条目。

编辑:

在这种情况下,对于上面的数组,所需的函数是:

f(a,b,c,d) {
       return array[(a+1) << 6 + (b+1) << 4 + (c+1) << 2 + (d+1)];
} 

答案 1 :(得分:2)

修改你的思维方式并认识到数组是一个函数,从一组索引到一组值。看着这种方式,你会想要像这样定义你的数组:

  array[0][1][0][-1] = value currently in array[1][0]
  array[-1][0][1][0] = value currently in array[1][1]
  etc

现在,不幸的是C不能直接索引具有任意整数范围的数组,但你可以通过以下两种方式之一来解决这个问题:

  • 定义one=1,zero=0,minusone=2等常量并使用数组表达式中的常量;
  • 使用偏移量,例如向每个索引添加1并在引用数组时减去它,例如数组[1-1] [2-1] [1-1] [0-1]。

在这两个中,前者可能更可取。

最后,这个数组将包含不在表中的值的条目,你必须在其中加入某种空代码。

答案 2 :(得分:1)

将您发布的表放在数组中,然后在循环中搜索正确的条目。这样您就可以将数据编码为数据而不是代码。

一旦映射规范发生变化,任何更聪明的方法都会产生过度的维护工作。除非证明循环的性能不高,否则我会使用循环。

答案 3 :(得分:0)

@James McLeod@High Performance Mark建议的方法外,您还可以使用自动生成的switch语句:

f(a,b,c,d) {
  switch(ind(a,b,c,d)) {
# include "cases.h"
  default: assert(0);
  };
}

ind()

enum { BASE = 3 };
int ind(int a, int b, int c, int d) {
  // ind() should produce the same result as the one from the script (see below)
  return (BASE*(BASE*(BASE*(a+1) + b+1) + c+1) + d+1);
}    

cases.h

case 48: return  array[1][0];
case 16: return  array[1][1];
case 32: return  array[1][2];
case 64: return  array[1][3];
case 66: return  array[2][0];
case 68: return  array[2][1];
case 14: return  array[2][2];
case 12: return  array[2][3];
case 46: return  array[3][0];
case 52: return  array[3][1];
case 34: return  array[3][2];
case 28: return  array[3][3];

cases.h可以通过以下脚本生成:

#!/usr/bin/env python
import csv, fileinput

# parse stdin or file(s) given at command-line as csv-file
rows = ((map(int, row[:-1]), row[-1])
        for row in csv.reader(fileinput.input(), delimiter='|') if row)

# function that arranges indexes in C-order
# . any function that produces unique integers will do
# . -1 <= n <= 1
ind = lambda args, base=3: reduce(lambda acc, n: base*acc + (n+1), args, 0)

# print cases for switch(ind(a,b,c,d)) statement
print '\n'.join("case %d: return %s;" % (ind(indexes), value) 
                for indexes, value in rows if value)

该脚本接受您问题中的表格作为输入。