Отображение 4-х переменных в массив - PullRequest
1 голос
/ 05 октября 2010

Мне нужно выбрать элемент aray на основе значений 4 переменных, как показано ниже, в 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 ]

3 голосов
/ 05 октября 2010

Я описал это решение способом, который несколько менее эффективен, чем его можно было бы объяснить; более краткая версия легко выводится из того, что я здесь показал.

Сопоставьте значения -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 - это неэффективность, которую я упомянул).

Так, например

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)

И тогда все, что вам нужно, это один поиск без цикла, чтобы получить правильный массив (или то, к чему вы обращаетесь).

В более кратком решении в таблице нет записей, указывающих на никуда.

EDIT:

В этом случае с массивом, как указано выше, желаемая функция:

f(a,b,c,d) {
       return array[(a+1) << 6 + (b+1) << 4 + (c+1) << 2 + (d+1)];
} 
2 голосов
/ 06 октября 2010

Пересмотрите свой образ мышления и узнайте, что массив - это функция, от набора индексов до набора значений. С этой точки зрения вы бы хотели определить свой массив следующим образом:

  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].

Из этих двух, вероятно, предпочтительнее первое.

Наконец, в этом массиве будут записи для значений, которых нет в вашей таблице, вам придется поместить в них какой-нибудь нулевой код.

1 голос
/ 05 октября 2010

Поместите таблицу, которую вы разместили, в массив и найдите в нем цикл для правильного ввода.Таким образом, вы будете кодировать данные как данные, а не как код.

Любой более умный метод вызовет излишнюю работу по обслуживанию, как только изменится ваша спецификация отображения.Если производительность цикла не окажется недостаточной, я бы использовал цикл.

0 голосов
/ 06 октября 2010

В дополнение к подходам, предложенным @ 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)

Скрипт принимает в качестве входных данных таблицу из вашего вопроса.

...