Skip to content

Commit

Permalink
optimize performance
Browse files Browse the repository at this point in the history
  • Loading branch information
bmesuere committed Jun 20, 2024
1 parent f825d53 commit a0a7215
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 9 deletions.
7 changes: 4 additions & 3 deletions lib/commands/base_command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Command } from "commander";
import { version } from '../../package.json';
import { readFileSync } from "fs";

/**
* This is a base class which provides a common interface for all commands.
Expand All @@ -11,8 +11,10 @@ import { version } from '../../package.json';
export abstract class BaseCommand {
public program: Command;
args: string[] | undefined;
version: string;

constructor(options?: { exitOverride?: boolean, suppressOutput?: boolean, args?: string[] }) {
this.version = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version;
this.program = this.create(options);
this.args = options?.args;
}
Expand All @@ -37,8 +39,7 @@ export abstract class BaseCommand {
writeErr: () => { }
});
}

program.version(version);
program.version(this.version);

return program;
}
Expand Down
25 changes: 19 additions & 6 deletions lib/commands/peptfilter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Option } from 'commander';
import { createInterface } from 'node:readline';
import { BaseCommand } from './base_command.js';

Expand All @@ -20,23 +19,37 @@ The input should have one peptide per line. FASTA headers are preserved in the o
.option("-c, --contains <amino acids>", "only retain peptides that contain all of the specified amino acids", (d) => d.split(""));
}

/**
* Performance note: this implementation takes 4 seconds to run on swissprot. It can be made faster by using line events instead of
* async iterators. This alternative implementation runs in 2.5 seconds. However, I decided that the async iterator implementation is
* both more readable and more in line with the implementation of the other commands.
*/
async run() {
this.parseArguments();
const minLen = this.program.opts().minlen;
const maxlen = this.program.opts().maxlen;
const lacks = this.program.opts().lacks || [];
const contains = this.program.opts().contains || [];

let output = [];
let i = 0;

for await (const line of createInterface({ input: process.stdin })) {
i++;
if (line.startsWith(">")) {
process.stdout.write(line + "\n");
continue;
output.push(line);
} else if (Peptfilter.checkLength(line, minLen, maxlen) && Peptfilter.checkLacks(line, lacks) && Peptfilter.checkContains(line, contains)) {
output.push(line);
}

if (Peptfilter.checkLength(line, minLen, maxlen) && Peptfilter.checkLacks(line, lacks) && Peptfilter.checkContains(line, contains)) {
process.stdout.write(line + "\n");
if (i % 1000 === 0) {
output.push("");
process.stdout.write(output.join("\n"));
output = [];
}
}

output.push("");
process.stdout.write(output.join("\n"));
}

static checkLength(line: string, minLen: number, maxlen: number): boolean {
Expand Down

0 comments on commit a0a7215

Please sign in to comment.