Approach via FilterXML()
For versions supporting LET
(MS 365) let's develop a basic formula logic based on ►FilterXML()
(assuming e.g. A1#
as spill range reference):
=LET(xml,"<all><i>"&TEXTJOIN("</i><i>",TRUE,A1#)&"</i></all>",xpath,"//i[.='pets']",COUNTA(FILTERXML(xml,Xpath)))
where
- xml creates a wellformed xml string (roughly comparable to a hmtl tag hierarchy)
- xpath defines the search expression string matching the value of each
<i>
node against 'pets'
via "//i[.='pets']"
COUNTA(FILTERXML(xml,Xpath))
counts the found elements of filterXML()
Caveats:
a) Hypothetical caveat
The formula above assumes that no individual name equals the generic name pets
, i.e.g that
there isn't any specific animal breed that is named "pets" as individual identifier.
If you want to exclude this improbable case, too just enter the following formula where the xpath
expression refers to the neighbour column elements:
=LET(xml,"<all><i>"&TEXTJOIN("</i><i>",TRUE,A1#)&"</i></all>",Xpath,"//i[.='pets' and position() mod 2 = 0]",COUNTA(FILTERXML(xml,Xpath)))
b) Integrate non-findings
Non-findings result in a #Value!
error, which COUNTA
, however would accept as 1 found element. On the other hand, enclosing FilterXML in an IF(IsError(FilterXML(..)),0,..)
condition would spill the whole result if there are findings n times, which can be avoided by integrating an error check like IF(err,0,COUNTA(FILTERXML(xml,Xpath)
:
Refined formula
=LET(spill,A1#,srch,"pets",xml,"<all><i>"&TEXTJOIN("</i><i>",TRUE,spill)&"</i></all>",Xpath,"//i[.='" & srch & "' and position() mod 2 = 0]",err,IsError(MATCH(srch,INDEX(spill,,2),0)),IF(err,0,COUNTA(FILTERXML(xml,Xpath))))
In order to make the formula more readable, I display it with line breaks:
=LET(
spill, A1#,
srch, "pets",
xml, "<all><i>"&TEXTJOIN("</i><i>",TRUE,spill)&"</i></all>",
Xpath, "//i[.='" & srch & "' and position() mod 2 =0]",
err, ISERROR(MATCH(srch,INDEX(spill,,2),0)),
IF(err, 0, COUNTA(FILTERXML(xml,Xpath)))
)
Recommended links
Alternative //edit as of 2021-11-16
Just for the sake of the art another approach translating all matches into the numeric value 1, which allows to sum them up. Note the unconventional double array argument src
in the second MATCH(src,src,0)
:
=LET(src,INDEX(A1#,,2),srch,"pets",row,MATCH(srch,src,0),err,ISERROR(row),IF(err,0,SUM(IF(MATCH(src,src,0)=row,1,0))))