# Cumulative count function?

**URL:** <https://discourse.julialang.org/t/cumulative-count-function/26979>\
**Category:** General Usage\
**Created:** [July 30, 2019, 2:07pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979 "2019-07-30T14:07:08Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![PaulMainwood](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paulmainwood/32/9578_2.png) [@PaulMainwood](https://discourse.julialang.org/u/PaulMainwood)\
**Post date:** [July 30, 2019, 2:07pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/1 "2019-07-30T14:07:08Z")

</div>

Is there a Julia function that can do a cumulative count of previous occurrences of each value an array?

That is, something that would behave like this (using a mixed array as an example):

```julia
cumcount([0, 5, 5, "foo", 5, 7, "bar", "foo"])
8-element Array{Int64,1}:
 1
 1
 2
 1
 3
 1
 1
 2

```

Before I get on and create something inefficient and bloated, I just want to check for anything elegant and beautiful that I’ve been unable to find so far.

---

<div class="post-metadata">

**Author:** ![kdyrhage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdyrhage/32/2326_2.png) [@kdyrhage](https://discourse.julialang.org/u/kdyrhage)\
**Post date:** [July 30, 2019, 2:51pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/2 "2019-07-30T14:51:29Z")

</div>

Depends on your definition of beautiful…

```julia
function f(A)
    d = Dict()
    function g(a)
        d[a] = get(f, a, 0) + 1
    end
    g.(A)
end

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 30, 2019, 2:57pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/3 "2019-07-30T14:57:13Z")

</div>

I think you meant `get(d, a, 0)`.

And in any case, it is _too beautiful_, and also quite clear, to the extent that even people relatively unfamiliar with Julia may just understand the code.

So we clearly need to make it uglier, eg

```julia
f(A) = (d = Dict(); (a -> d[a] = get(d, a, 0) + 1).(A))

```

---

<div class="post-metadata">

**Author:** ![non-Jedi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/non-jedi/32/3645_2.png) [@non-Jedi](https://discourse.julialang.org/u/non-Jedi)\
**Post date:** [July 30, 2019, 3:10pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/4 "2019-07-30T15:10:35Z")

</div>

I’m not sure broadcasting guarantees left-associativity. So you might  
want `[g(a) for a in A]` instead of `g.(A)`.

---

<div class="post-metadata">

**Author:** ![cormullion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cormullion/32/49131_2.png) [@cormullion](https://discourse.julialang.org/u/cormullion)\
**Post date:** [July 30, 2019, 4:04pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/5 "2019-07-30T16:04:46Z")

</div>

“Ugly” competition? - I can play this game:

```julia
[findall(isequal(A[x]), A[1:x]) |> length for x in eachindex(A)]

```

---

<div class="post-metadata">

**Author:** ![under-Peter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/under-peter/32/3626_2.png) [@under-Peter](https://discourse.julialang.org/u/under-Peter)\
**Post date:** [July 30, 2019, 4:21pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/6 "2019-07-30T16:21:11Z")

</div>

Guaranteed left-associative:

```julia
julia> cumcount(xs) = foldl(xs, init = (Dict(), [])) do (d,l), x
           d[x] = get(d,x,0) + 1
           push!(l,d[x])
           (d,l)
       end[2]
cumcount (generic function with 1 method)

julia> cumcount([0, 5, 5, "foo", 5, 7, "bar", "foo"])
8-element Array{Any,1}:
 1
 1
 2
 1
 3
 1
 1
 2

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 30, 2019, 4:31pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/7 "2019-07-30T16:31:45Z")

</div>

Isn’t that O(n^2)?

By the way, the (unwritten) rules of the competition are:

1. it should do something well,
2. but have a subtle potential bug (as pointed out by @non-Jedi — if broadcasting does not ensure sequential mapping, a lot of code will break, hopefully non-deterministically),
3. have enough punctuation to complete an e e cummings poem to fully formed sentences.

Being bug-free, your code is disqualified by (2) 😉

---

<div class="post-metadata">

**Author:** ![kdyrhage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdyrhage/32/2326_2.png) [@kdyrhage](https://discourse.julialang.org/u/kdyrhage)\
**Post date:** [July 31, 2019, 7:50am UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/8 "2019-07-31T07:50:31Z")

</div>

This is very confusing, I have no idea how the `f` got there. I tested different versions (including yours, but I deemed it too beautiful for the public eye) and benchmarked them and everything, yet somehow I got it wrong when copying it. Is this Muphry’s law at work?

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [July 31, 2019, 9:46pm UTC](https://discourse.julialang.org/t/cumulative-count-function/26979/9 "2019-07-31T21:46:51Z")

</div>

Not sure if it’s ugly or beautiful but transducers are good solution for this kind of tasks

```julia
using Transducers
using BangBang

xf = ScanEmit(Dict{Union{},Union{}}()) do d, x
    c = get(d, x, 0) + 1
    c, setindex!!(d, c, x)
end

collect(xf, [0, 5, 5, "foo", 5, 7, "bar", "foo"])

```
