根据循环中的条件应用表达式

时间:2015-10-20 15:25:42

标签: c r

我猜这个问题肯定已被问过几次,但我找不到任何东西。

我有一个依赖于参数(caseset)的函数,它可以是两种不同的类型。根据其性质,在循环中我需要执行操作而不是另一个操作。由于对象的性质在开始时是已知的,因此在循环中每次都有if语句看起来效率低且不优雅。理想情况下,我每次都应用正确的表达式并在循环的顶部选择它。这是一个代码,可以了解我的目标。

SEXP doSomething(SEXP anObject, SEXP caseset, SEXP isMat) {
  /*
  * here anObject is an external pointer to a C structure,
  * caseset is either a character matrix or a data.frame made of character columns.
  */
 int i,j,nrow,ncol;
 int isMatrix = LOGICAL(isMat)[0];
 const char *field;
 /*
  * Determine the number of rows and columns in each case
 */
 if (isMatrix) {
   ncol = length(VECTOR_ELT(getAttrib(caseset,R_DimNamesSymbol),1));
   nrow = length(caseset)/ncol;
 } else {
   ncol = length(caseset);
   nrow = length(VECTOR_ELT(caseset,0));
 }
 for (i=0;i<nrow;i++) {
   for (j=0;j<ncol;j++) {
     if (isMatrix) {
       field = CHAR(STRING_ELT(caseset,j*nrow+i));
     } else {
       field = CHAR(STRING_ELT(VECTOR_ELT(caseset,j),i));
     }
     /*
      * Do stuff involving field and anObject
     */    
   }
 }
 return result;
}

我正在写一个可以从R调用的C函数。我正在传递R对象(SEXP类型)。 caseset对象可以是矩阵或data.frame。我当时正在处理一行,因为两个对象以非常不同的方式存储它们的元素,要获得表的(i,j)值,您必须以不同方式移动。请注意每次if条件(每次doSomething的调用都会产生相同的结果)。剩下的功能很长。

我当然可以:

  • if条件移出循环并重写两个相同的代码块(一行除外),具体取决于isMatrix的值;
  • 写两个几乎相同的函数,并根据caseset的性质“发送”正确的函数。

然而,上述两种选择对我来说都不合适。我更喜欢让你在循环中应用正确的行而不必每次都检查条件而不必重写两次代码。

2 个答案:

答案 0 :(得分:2)

C并不完全以优雅着称。其他语言可能允许您使用某种迭代器。检查isMatrix两次也不错。但是,当然您可能需要检查更多次,或者可能需要支持更多类型。

考虑使用基于isMat的两个内部函数:

SEXP doSomething(SEXP anObject, SEXP caseset, SEXP isMat) {
/*
 * here anObject is an external pointer to a C structure,
 * caseset is either a character matrix or a data.frame made of character     columns.
 */
  return LOGICAL(isMat)[0] ? doSomethingMatrix(anObject,caseset) : doSomethingFrame(anObject,caseset);
}
static doSomethingMatrix(SEXP anObject, SEXP caseset) {
  int i,j,nrow,ncol;
  const char *field;

  ncol = length(VECTOR_ELT(getAttrib(caseset,R_DimNamesSymbol),1));
  nrow = length(caseset)/ncol;

  for (i=0;i<nrow;i++) {
    for (j=0;j<ncol;j++) {
      field = CHAR(STRING_ELT(caseset,j*nrow+i));

      // Share the long processing code between the two functions
      doStuffField(anObject,field);
    }
  }
  return result;
}

答案 1 :(得分:0)

您可以使用函数指针数组。 例如,要编写计算器,而不是:

if (c == '+')
   return (a + b);
elif (c == '-')
   return (a - b);
...

您可以执行以下操作:

char *op = {'+', '-', '/', '*', '%', 'whatever you want', NULL};
for (int i=0, op[i] && op[i] != c, i++};
if (op[i])
   return (my_function_ptr[i](a, b));

它会在数组中调用函数编号'i'。