Getting count of occurrences for X in string
Asked Answered
V

8

12

Im looking for a function like Pythons

"foobar, bar, foo".count("foo")

Could not find any functions that seemed able to do this, in a obvious way. Looking for a single function or something that is not completely overkill.

Vanward answered 3/6, 2014 at 11:49 Comment(1)
I don't see how this Julia question is related to Objective C? Neither is the solution for said question close to the answer I am asking for.Vanward
R
9

This is now just count:

julia> count("foo", "foobar, bar, foo")
2
Reorganize answered 3/6, 2014 at 21:3 Comment(1)
Woops, seems like i derped on split, expected other output. That is the better solution that is not using RE, i approve.Vanward
E
14

Julia-1.0 update:

For single-character count within a string (in general, any single-item count within an iterable), one can use Julia's count function:

julia> count(i->(i=='f'), "foobar, bar, foo")
2

(The first argument is a predicate that returns a ::Bool).

For the given example, the following one-liner should do:

julia> length(collect(eachmatch(r"foo", "bar foo baz foo")))
2

Julia-1.7 update:

Starting with Julia-1.7 Base.Fix2 can be used, through ==('f') below, as to shorten and sweeten the syntax:

julia> count(==('f'), "foobar, bar, foo")
2
Expressage answered 22/1, 2019 at 1:49 Comment(0)
W
11

What about regexp ?

julia> length(matchall(r"ba", "foobar, bar, foo"))
2
Witherspoon answered 3/6, 2014 at 15:10 Comment(4)
That is the one "sane" solution i ended up with, but i'ts kinda of annoying having to escape RE chars (really annoying if you are using the function without knowing what the string you pass in is). Also i feel like using RE for something like this is kind of overkill, though its better than searching through the string manually.Vanward
You may encapsulate this code in a function to hide the regexWitherspoon
Of course there will be used a function the problem is that julia> matchall(Regex("Dots."), "Dots are cool") 1-element Array{SubString{UTF8String},1}: "Dots " (I hope the code tags work) Should not match, and it does because of the '.', escaping RE characters is not hard, but there should be a simpler solution than using RE, at least in my opinion.Vanward
I get a ERROR: UndefVarError: matchall not defined. How to get it defined?Expressage
R
9

This is now just count:

julia> count("foo", "foobar, bar, foo")
2
Reorganize answered 3/6, 2014 at 21:3 Comment(1)
Woops, seems like i derped on split, expected other output. That is the better solution that is not using RE, i approve.Vanward
Y
2

Adding an answer to this which allows for interpolation:

julia> a = ", , ,";
julia> b = ",";
julia> length(collect(eachmatch(Regex(b), a)))
3

Actually, this solution breaks for some simple cases due to use of Regex. Instead one might find this useful:

"""
count_flags(s::String, flag::String)

counts the number of flags `flag` in string `s`.
"""
function count_flags(s::String, flag::String)
counter = 0
for i in 1:length(s)
  if occursin(flag, s)
    s = replace(s, flag=> "", count=1)
    counter+=1
  else
    break
  end
end
return counter
end
Yettayetti answered 19/7, 2019 at 15:52 Comment(0)
W
1

Sorry to post another answer instead of commenting previous one, but i've not managed how to deal with code blocks in comments :)

If you don't like regexps, maybe a tail recursive function like this one (using the search() base function as Matt suggests) :

function mycount(what::String, where::String)
  function mycountacc(what::String, where::String, acc::Int)
    res = search(where, what)
    res == 0:-1 ? acc : mycountacc(what, where[last(res) + 1:end], acc + 1)
  end
  what == "" ? 0 : mycountacc(what, where, 0)
end
Witherspoon answered 3/6, 2014 at 21:47 Comment(0)
G
1

This is simple and fast (and does not overflow the stack):

function mycount2(where::String, what::String)
    numfinds = 0
    starting = 1
    while true
        location = search(where, what, starting)
        isempty(location) && return numfinds
        numfinds += 1
        starting = location.stop + 1
    end
end
Garlicky answered 29/11, 2016 at 14:55 Comment(0)
C
1

one liner: (Julia 1.3.1):

julia> sum([1 for i = eachmatch(r"foo", "foobar, bar, foo")])
2
Connatural answered 4/1, 2020 at 20:17 Comment(0)
F
1

Since Julia 1.3, there has been a count method that does exactly this.

  count(
      pattern::Union{AbstractChar,AbstractString,AbstractPattern},
      string::AbstractString;
      overlap::Bool = false,
  )

  Return the number of matches for pattern in string.  
  This is equivalent to calling length(findall(pattern, string)) but more
  efficient.

  If overlap=true, the matching sequences are allowed to overlap indices in the
  original string, otherwise they must be from disjoint character ranges.

  │ Julia 1.3
  │
  │  This method requires at least Julia 1.3.
julia> count("foo", "foobar, bar, foo") 
2

julia> count("ana", "bananarama")
1

julia> count("ana", "bananarama", overlap=true)
2

Frequency answered 26/5, 2022 at 5:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.