我需要创建一个应用程序来读取CSV文件,转换其数据,然后将其作为另一个CSV文件输出。
输入格式如下:
13:25:37 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
13:25:38 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
... so on
对于那些UNIX粉丝的用户,您会将其识别为控制台命令uptime
的输出。
我想要的输出格式如下:
RowNum, Avg Load
1,0.02
2,0.02
第一列是CSV中的行号,第二列是平均负载的数字部分:0.02。
要忽略所有其他列。
尽可能在功能上尝试这样做,我决定使用ramda。
至少可以说这是一个挑战。现在,我的代码有几个结构问题,但我想关注main
函数,它不起作用。每次执行代码时都会收到错误:
index.js:54
.then( () => console.log("Done!") )
^
TypeError: main(...).then is not a function
这令人困惑,因为在我传递给R.ifElse
的两个函数中,我都返回了一个Promise。
const fs = require("fs");
const csvReader = require("csvreader");
const R = require("ramda");
const isString = require("lodash.isstring");
const { promisify } = require("util");
const argv = require("minimist")(process.argv.slice(2));
const appedFileAsync = promisify( fs.appendFile );
const createProcessData = () => {
const stringifyArray = array => `${array.toString()}\n`;
const write = str => fs.appendFileSync( argv.outputFile, str );
const getAvg = R.pipe(
R.replace("load average:", ""),
R.trim
);
let elapsedTime = 1;
const transform = list => [ elapsedTime++, getAvg ( R.nth( 3, list ) ) ];
return R.pipe(
transform,
stringifyArray,
write
);
};
const printHelp = () => {
console.log(`
=== MAN HELP ===
Usage: npm start -- --inputFile input.csv --outputFile output.csv
--inputFile: location of an input file in CSV format
--outputFile: location of an output file to append the new information to.
If this file does not exist, it will be created.
`);
return Promise.resolve();
};
const execute = () => appedFileAsync( argv.outputFile, "Time, Avg Load\n" )
.then( ( ) => csvReader.read( argv.inputFile, createProcessData() ) );
const main = () => {
const isInvalidFileName = R.anyPass( [ R.isNil, R.isEmpty, R.pipe ( isString, R.not ) ] );
const hasInvalidArgs = R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) );
return R.ifElse(
hasInvalidArgs,
printHelp,
execute
);
};
main()
.then( () => console.log("Done!") )
.catch( console.error );
答案 0 :(得分:2)
这是考虑ifElse
:
const ifElse = (predicate, consequent, alternative) =>
(...val) => predicate(...val) ? consequent(...val) : alternative(...val);
所以
const comp = ifElse(
(a, b) => a < b,
(a, b) => `${a} is smaller than ${b}`,
(a, b) => `${a} is at least as large as ${b}`
)
comp(12, 7) //=> "12 is at least as large as 7"
重点是ifElse
的第一个参数是函数。但是你传递了它的结果:
R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) )
现在通常,either
会返回一个函数。但这取决于你向它提供功能。假设如果您不提供函数,您就知道自己在做什么,并且正在使用ap
和map
方法提供容器类型,因此either
稍微更通用。但是你提供的布尔值是isInvalidFileName( argv.inputFile )
的结果。那时行为没有明确定义。也许这应该改变,但Ramda的哲学通常是垃圾垃圾。因此无论出于何种原因,either
调用都会返回[undefined]
。
这意味着您将[undefined]
作为谓词函数提供给ifElse
。当您尝试调用它时,您应该收到错误。我没有试图追查为什么那个错误被你看到的错误所掩盖。
至于如何使用Ramda解决这个问题,我不确定从哪里开始。这与Ramda一贯的风格相差甚远。如果没有别的,那些不接受参数的函数在Ramda中极为罕见。我想我会用一个接受argv.inputFile
和argv.outputFile
的函数启动Ramda部分,作为单个对象或者可能作为单个对象argv
。