计数出现次数值子字符串包含在整个对象中



我想计数子字符串对象值,即整个对象包含字符串而不是键等于字符串。XSLT中有效的Xpath应该是

count(//v[contains(.,current-grouping-key())])

但是我不能在javascript中找出这个

我试了如下:

const obj = 
[ { v: 'Bla Blu Bli' },
{ v: 'Bla Blu Bli' },
{ v: 'Bla Blu' },
{ v: 'Bla Bli' }
];
const count = obj.reduce( function(sums,entry) {
sums[entry.v] = (sums[entry.v] || 0) + 1;
return sums;
},{});

console.log(count)

但是这只计算精确的字符串。所以我得到:

"Bla Blu Bli": 2,
"Bla Blu": 1,
"Bla Bli": 1

不是

"Bla Blu Bli": 2,
"Bla Blu": 3,
"Bla Bli": 3

是否有一种方法来计数子字符串,而不是确切的值?

第二个版本应该更快。

(你写我有100k+值,在评论中)

它只创建一个不同序列的数组,与相同序列的拷贝数相关联
并通过将包含相同值的其他集合的拷贝数添加到该数量来遍历该数组,
通过只选择大小较大的集合。

我使用Set元素是因为根据文档,[Set].has(value)比[array].includes(value)

快。

const obj = 
[ { v: 'Bla Blu Bli' }
, { v: 'Bla Bli Blu' }
, { v: 'Bla Blu'     }
, { v: 'Bla Bli'     }
];
const counts = obj
.reduce((r,o) => // create arr with unique sets with count of copies
{
let 
arr = o.v.split(' ')
, sam = r.find(x=>(x.s.size===arr.length) && arr.every(a=>x.s.has(a)) )
;
if (sam)  ++sam.n   // + one more copy
else      r.push({arr, s:new Set(arr), n:1 })
// next step need  arr and set to avoid losing time 
// in conversion operations between array and Set
return r
},[]) 
.reduce((c,e,_,all) =>
{
c[e.arr.join(' ')] = e.n  
+ all.reduce((s,x)=>((x.s.size > e.s.size && e.arr.every(a=>x.s.has(a))) ? s + x.n : s),0)
// try to find includings, only in largest sets
return c
},{})  
console.log(  counts  )
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

你可以这样写:

const obj = 
[ { v: 'Bla Blu Bli' }
, { v: 'Bla Blu Bli' }
, { v: 'Bla Blu'     }
, { v: 'Bla Bli'     }
];
const counts = obj
.map(e=>e.v.split(' ').sort((a,b)=>a.localeCompare(b)))
.reduce((r,a,_,all)=>
{
let terms = a.join(' ')
if (!r[terms])
r[terms] = all.reduce((c,x)=>c+(a.every(v=>x.includes(v))?1:0),0);
return r
},{})

console.log(  counts )
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

您必须使用indexOf或类似的方法来查看字符串中是否存在子字符串。

的例子:

obj = [
{
"v": "Bla † Blu † Bli"
},
{
"v": "Bla † Blu † Bli"
},
{
"v": "Bla † Blu"
}
]
const counts = Object.fromEntries(
obj.map(({v}) => [v, obj.reduce((acc, el) => {
if (el.v.indexOf(v) > -1) acc++;
return acc;
}, 0)])
);
console.log(counts);

最新更新