所以我现在正在经历一些逻辑上的难题。这是我试图解决的问题
问题
我正在读取PDB文件,当它浏览文件时,它会创建文件中所有链的列表。该列表看起来像这样
chainIdList = [A, E, D, F, G, H];
长度可以变化。
我有序列中每个残基的所有chainIds的另一个列表,数据是我做的字典,看起来像这样
chainResidue = {"chainId" : chainId, "residueNumber" : residueNumber}
chainResidue = { "A", "4"}
所以我想要做的是遍历chainResidues列表并检查chainResidue.chainId是否在chainList中。如果是,则创建一个匹配的chainId的新列表,然后将所有residualNumbers附加到该列表。
如果这有意义吗?
所以最后看起来像
A = [ 4, 6, 7, 8, ... and so on];
E = [ 9, 10];
到目前为止的代码
for (var i = 0; i < chainResidue.length; ++i) {
for (var j = 0; j < chainList.length; ++j) {
if (chainResidue[i].chainId === chainList[j]) {
//Append value of the chainResidue[i].residueName into chainList[j] make a list of lists?
}
}
}
示例数据
ATOM 3434 CA LEU Y 17 -3.567 5.653 33.836 1.00 28.21 C
ATOM 3435 C LEU Y 17 -3.114 6.290 32.530 1.00 31.33 C
ATOM 3436 O LEU Y 17 -2.020 6.873 32.474 1.00 26.01 O
ATOM 3437 CB LEU Y 17 -2.620 4.575 34.233 1.00 29.46 C
ATOM 3438 CG LEU Y 17 -2.610 4.263 35.705 1.00 33.42 C
ATOM 3439 CD1 LEU Y 17 -1.430 3.363 35.960 1.00 40.68 C
ATOM 3440 CD2 LEU Y 17 -2.351 5.483 36.559 1.00 40.12 C
ATOM 3441 N ASP Y 18 -3.926 6.263 31.454 1.00 30.62 N
ATOM 3442 CA ASP Y 18 -3.487 6.866 30.205 1.00 31.46 C
我只是拉着&#34; Y&#34;以及与17和18相对应的数字。
答案 0 :(得分:2)
您可以使用此ES6脚本:
// Sample data
var chainIdList = ['A', 'E', 'D', 'F', 'G', 'H'];
var chainResidue = [
{"chainId" : "A", "residueNumber" : 24},
{"chainId" : "E", "residueNumber" : 18},
{"chainId" : "A", "residueNumber" : 9},
{"chainId" : "A", "residueNumber" : 15}
];
// Create the empty lists to start with, per letter
var chainIdObj = chainIdList.reduce( (obj, id) => (obj[id] = [], obj), {} );
// Populate those lists with residue numbers
var result = chainResidue.reduce( (res, obj) => (res[obj.chainId] ? res[obj.chainId].push(obj.residueNumber) : 0, res), chainIdObj);
console.log(result);
主要有两个阶段:
chainIdList.reduce
遍历输入数组,并为每个元素调用为其提供的函数。该函数的第一个参数始终是前一个调用的结果。第一次,没有先前的调用,然后它以我们提供的空对象({}
)作为reduce
的第二个参数开始。
传递给reduce
的函数如下所示:
(obj, id) => (obj[id] = [], obj)
这实际上是2015年由EcmaScript6引入的新符号。在“较旧”的语法中,它看起来像这样:
function (obj, id) { return obj[id] = [], obj; }
函数体使用逗号运算符,与return
一起它实际上等同于此代码:
obj[id] = [];
return obj;
因此,综合起来,obj
的值以{}
开头,然后在每次迭代中为其定义属性。在第一次迭代之后它是
{ 'A': [] }
...并返回到reduce
内部,以便它在下一次迭代中作为参数传递,等等。在最后一次迭代中返回的对象将作为整个{的返回值返回。 {1}}致电。
现在我们reduce
等于:
chainIdObj
第二阶段用于填充上述结构中的数组。同样,迭代是{
"A": [],
"E": [],
"D": [],
"F": [],
"G": [],
"H": []
}
;这次超过reduce
。为chainResidue
中的每个对象执行的函数是:
chainResidue
第一个参数((res, obj) => (res[obj.chainId] ? res[obj.chainId].push(obj.residueNumber) : 0, res)
)的第一个值是这次未使用res
初始化,而是使用前一个阶段的结果:{}
。上面的函数检查我们正在查看的对象的chainIdObj
属性值是否与chainId
中的条目匹配(即在res
中)。如果是这样(chainIdObj
),相应的?
将被推送到我们刚检查过的数组。在另一种情况下(residueNumber
)什么都不应该发生。但是由于三元运算符需要第三个表达式,我们只是放:
:无论如何,表达式的值被忽略,所以这只是一个语法填充。
最后,逗号运算符再次用于确保0
对象返回到res
内部,因此我们在下一次迭代中再次获取它。最终结果是最后一次迭代的结果,并由reduce
返回。它被分配到reduce
。
这是在控制台中输出的东西。
有些人喜欢在可能的情况下避免变量赋值,并将它们的使用限制为函数参数。使用上述元素,您可以编写如下代码:
result
答案 1 :(得分:0)
虽然你已经有了答案,但我建议不要使用Array#reduce
,因为它总是返回相同的对象而不是必需的。
// Sample data
var chainIdList = ['A', 'E', 'D', 'F', 'G', 'H'],
chainResidue = [{ chainId: "A", residueNumber: 24 }, { chainId: "E", residueNumber: 18}, { chainId: "A", residueNumber: 9 }, { chainId: "A", residueNumber: 15 }],
result = Object.create(null);
chainIdList.forEach(a => result[a] = []);
chainResidue.forEach(a => result[a.chainId] && result[a.chainId].push(a.residueNumber));
console.log(result);