636275856908b6b71134527c9c410acb82682d08 kent Fri Feb 20 15:29:24 2015 -0800 Adding several routines that work across a column into library including one to see if column is entirely numeric, another to figure out how wide it is, and a third to sort on a column. diff --git src/lib/fieldedTable.c src/lib/fieldedTable.c index 5037bcd..ac0d492 100644 --- src/lib/fieldedTable.c +++ src/lib/fieldedTable.c @@ -53,30 +53,128 @@ struct fieldedRow *fr; lmAllocVar(lm, fr); lmAllocArray(lm, fr->row, rowSize); fr->id = id; int i; for (i=0; i<rowSize; ++i) fr->row[i] = lmCloneString(lm, row[i]); /* Add it to end of list using cursor to avoid slReverse hassles. */ *(table->cursor) = fr; table->cursor = &fr->next; return fr; } +int fieldedTableMaxColChars(struct fieldedTable *table, int colIx) +/* Calculate the maximum number of characters in a cell for a column */ +{ +if (colIx >= table->fieldCount) + errAbort("fieldedTableMaxColChars on %d, but only have %d columns", colIx, table->fieldCount); +int max = strlen(table->fields[colIx]) + 1; +struct fieldedRow *fr; +for (fr = table->rowList; fr != NULL; fr = fr->next) + { + char *val = fr->row[colIx]; + if (val != NULL) + { + int len = strlen(val); + if (len > max) + max = len; + } + } +return max; +} + +boolean fieldedTableColumnIsNumeric(struct fieldedTable *table, int fieldIx) +/* Return TRUE if field has numeric values wherever non-null */ +{ +struct fieldedRow *fr; +boolean anyVals = FALSE; +for (fr = table->rowList; fr != NULL; fr = fr->next) + { + char *s = fr->row[fieldIx]; + if (s != NULL) + { + anyVals = TRUE; + if (!isNumericString(s)) + return FALSE; + } + } +return anyVals; +} + +static int slPairCmpNumbers(const void *va, const void *vb) +/* Compare slPairs where name is interpreted as floating point number */ +{ +const struct slPair *a = *((struct slPair **)va); +const struct slPair *b = *((struct slPair **)vb); +double aVal = atof(a->name); +double bVal = atof(b->name); +double diff = aVal - bVal; +if (diff < 0) + return -1; +else if (diff > 0) + return 1; +else + return 0; +} + + +void fieldedTableSortOnField(struct fieldedTable *table, char *field, boolean doReverse) +/* Sort on field. Distinguishes between numerical and text fields appropriately. */ +{ +/* Figure out field position */ +int fieldIx = stringArrayIx(field, table->fields, table->fieldCount); +if (fieldIx < 0) + fieldIx = 0; +boolean fieldIsNumeric = fieldedTableColumnIsNumeric(table, fieldIx); + +/* Make up pair list in local memory which points to rows */ +struct lm *lm = lmInit(0); +struct slPair *pairList=NULL, *pair; +struct fieldedRow *fr; +for (fr = table->rowList; fr != NULL; fr = fr->next) + { + char *val = emptyForNull(fr->row[fieldIx]); + lmAllocVar(lm, pair); + pair->name = val; + pair->val = fr; + slAddHead(&pairList, pair); + } +slReverse(&pairList); + +/* Sort this list. */ +if (fieldIsNumeric) + slSort(&pairList, slPairCmpNumbers); +else + slSort(&pairList, slPairCmpCase); +if (doReverse) + slReverse(&pairList); + +/* Convert rowList to have same order. */ +struct fieldedRow *newList = NULL; +for (pair = pairList; pair != NULL; pair = pair->next) + { + fr = pair->val; + slAddHead(&newList, fr); + } +slReverse(&newList); +table->rowList = newList; +lmCleanup(&lm); +} + struct fieldedTable *fieldedTableFromTabFile(char *fileName, char *reportFileName, char *requiredFields[], int requiredCount) /* Read table from tab-separated file with a #header line that defines the fields. Ensures * all requiredFields (if any) are present. The reportFileName is just used for error reporting and * should be NULL for most purposes. This is used by edwSubmit though which * first copies to a local file, and we want to report errors from the remote file. * We do know the remote file exists at least, because we just copied it. */ { /* Open file with fileName */ struct lineFile *lf = lineFileOpen(fileName, TRUE); /* Substitute in reportFileName for error reporting */ if (reportFileName != NULL) { if (differentString(reportFileName, fileName))