# Filter by array of tuples

**URL:** <https://discourse.julialang.org/t/filter-by-array-of-tuples/19534>\
**Category:** New to Julia\
**Created:** [January 11, 2019, 7:47pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534 "2019-01-11T19:47:22Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rssdev10](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@rssdev10](https://discourse.julialang.org/u/rssdev10)\
**Post date:** [January 11, 2019, 7:47pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/1 "2019-01-11T19:47:22Z")

</div>

I found weird behavior of tuple mapping on variables. I need to get indices of elements by a rule.

This code is working fine too:

```julia
names = ["aa", "ab", "ca"]
filter((i) -> startswith(i[2], "a"), collect(enumerate(names)))

```

I specified one variable for the tuple and, next I’m taking value by index - i[2]. And it is not good.

But the code:

```julia
names = ["aa", "ab", "ca"]
filter((i, name) -> startswith(name, "a"), collect(enumerate(names)))

```

doesn’t work. I’m getting error:

```julia
ERROR: MethodError: no method matching (::getfield(Main, Symbol("##143#144")))(::Tuple{Int64,Symbol})
Closest candidates are:
  #143(::Any, ::Any) at none:1
Stacktrace:
 [1] mapfilter(::getfield(Main, Symbol("##143#144")), ::typeof(push!), ::Array{Tuple{Int64,Symbol},1}, ::Array{Tuple{Int64,Symbol},1}) at ./abstractset.jl:336
 [2] filter(::Function, ::Array{Tuple{Int64,Symbol},1}) at ./array.jl:2352
 [3] top-level scope at none:0

```

At the same time, following code works fine:

```julia
names = ["aa", "ab", "ca"]
@show arr = collect(enumerate(names))
(i, name) = arr[1]
@show i
@show name

```

I’m getting:

```julia
arr = collect(enumerate(names)) = Tuple{Int64,String}[(1, "aa"), (2, "ab"), (3, "ca")]
i = 1
name = "aa"

```

Is it a bug or I’m doing something wrong?  
Julia 1.0.3

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 11, 2019, 8:37pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/2 "2019-01-11T20:37:43Z")

</div>

As you probably know, the syntax

```julia
i -> startswith(i[2], "a")

```

creates an anonymous function similar to

```julia
function __anonymous__ (i)
      startswith(i[2], "a")
end

```

Now the syntax

```julia
(i, name) -> startswith(name, "a")

```

creates an anonymous function taking _two_ arguments (as opposed to a function taking one argument which is a tuple of two values, as in the first, working, case):

```julia
function __anonymous__ (i, name)
      startswith(name, "a")
end

```

Hence the error message telling you that the correct method is not found: since `enumerate` produces a collection of `Tuple{Int64,String}`, this is what your function has to take as argument.

  

So if you want to “deconstruct” the tuple, you have to do it inside the function (at least I don’t know of any other way):

```julia
julia> filter(tuple-> let (i, name)=tuple; startswith(name, "a") end,
              collect(enumerate(["aa", "ab", "ca"])))
2-element Array{Tuple{Int64,String},1}:
 (1, "aa")
 (2, "ab")

```

  

BTW, using `names` as the name of your test variable is probably not a good idea, as it collides with `Base.names`

---

<div class="post-metadata">

**Author:** ![rssdev10](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@rssdev10](https://discourse.julialang.org/u/rssdev10)\
**Post date:** [January 11, 2019, 9:09pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/3 "2019-01-11T21:09:08Z")

</div>

ok, thanks. Explicit assignment is a little bit non obvious way to expand arguments for lambda. Too many code…

Regarding names, sure. It was a fragment of code for DataFrame column names analysis. Therefore it was `names`.

And regarding error message, it is really hard to understand that `(::getfield(Main, Symbol("##143#144")))` means inappropriate number of arguments…

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [January 11, 2019, 9:22pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/4 "2019-01-11T21:22:23Z")

</div>

You can create an anonymous function that does the tuple de-structuring if you want, it just requires an extra tailing comma in the arguments:

```julia
julia> f = ((index, item),) -> println("index: $index, item: $item")
#9 (generic function with 1 method)

julia> map(f, enumerate(["a", "b", "c"]))
index: 1, item: a
index: 2, item: b
index: 3, item: c

```

You need the comma to differentiate `((a, b),) -> ...`, which is a function taking a single argument (a tuple) from `(a, b) -> ...`, which is a function taking _two_ arguments, as mentioned above.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 11, 2019, 9:23pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/5 "2019-01-11T21:23:34Z")

</div>

> [@rssdev10](#):
>
> And regarding error message, it is really hard to understand that `(::getfield(Main, Symbol("##143#144")))` means inappropriate number of arguments…

Yes, I understand this message might be confusing. Here is how to read it:

```julia
no method matching (::getfield(Main, Symbol("##143#144")))(::Tuple{Int64,Symbol})
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
# this part is the "anonymous" this is the argument
# function's "name": not type that Julia was
# interesting expecting: a tuple
Closest candidates are:
# This is what Julia found:
  %143(::Any, ::Any) at none:1
# ^^^^ ^^^^^^^^^^^
# name two args
# instead of a tuple

```

But I agree that it is hard to read…

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [January 11, 2019, 9:26pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/6 "2019-01-11T21:26:06Z")

</div>

That’s a really nice annotation. I bet it would be possible to modify julia to produce something like that by default. The rust compiler does a great job of using a little bit of annotation and ascii art to make its error messages much friendlier, and I bet we could do the same.

---

<div class="post-metadata">

**Author:** ![rssdev10](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@rssdev10](https://discourse.julialang.org/u/rssdev10)\
**Post date:** [January 12, 2019, 6:20am UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/7 "2019-01-12T06:20:17Z")

</div>

Thank you for the answers.  
`((index, item),) -> ...` is much better than `tuple -> let (index, item) = tuple; ...`

It is still confusing syntax comparing with other languages experience.

It would be good to have just differentiating between:  
`tuple -> something(tuple[2]) ...`  
and  
`(index, item) -> ...`  
in any case it is visually distinguishable by brackets.

And already syntax like `((index, item)) -> ...` or `tuple(index, item) -> ....` is more clear than `((index, item),) ->...` with additional comma… But ok. May be it is just because of bad interpreting of the error messages…

> ERROR: MethodError: no method matching (::getfield(Main, Symbol(“##143#144”)))(::Tuple{Int64,Symbol})  
> Closest candidates are:  
> #143(::Any, ::Any) at none:1

I got it. So, Julia tried to find some function with `(::Tuple{Int64,Symbol})` argument. And next message about `Closest candidates: #143(::Any, ::Any)` is actually for Julia but not for me… Because of it is function provided by me. And `candidates` should be selected by Julia but not by me…

So here a message like `Expected (::Tuple{Int64,Symbol}) but found arguments (::Any, ::Any)` would be better. No clue how hard to fix it in the compiler. But signs to detect it are internal name of function with the prefix #… and the only candidate function.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 12, 2019, 10:09am UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/8 "2019-01-12T10:09:49Z")

</div>

> [@ffevotte](#):
>
> BTW, using `names` as the name of your test variable is probably not a good idea, as it collides with `Base.names`

In that case, it is probably best to avoid `tuple` as a variable name, too. I guess it does not cause any problems in practice, when it goes out of scope, but it’s quite confusing to read.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 12, 2019, 11:04am UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/9 "2019-01-12T11:04:46Z")

</div>

Are you particularly interested in the tuple issue, or are you mainly looking for a way to find the indices? In the latter case, you can forget all about the `filter` and the `enumerate` and the tuples, and just use `findall`.

---

<div class="post-metadata">

**Author:** ![rssdev10](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@rssdev10](https://discourse.julialang.org/u/rssdev10)\
**Post date:** [January 12, 2019, 11:37am UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/10 "2019-01-12T11:37:03Z")

</div>

yes, thanks. I was really looking for findall.

```julia
findall(name -> startswith(name, "a"), ["aa", "ab", "ca"])

```

looks much simpler.

But the topic about tuples usage syntax/errors diagnosis is really non obvious. So, the explanations might be useful for some other things.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 12, 2019, 4:33pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/11 "2019-01-12T16:33:23Z")

</div>

> [@rssdev10](#):
>
> `findall(name -> startswith(name, "a"), ["aa", "ab", "ca"])`

If your matching string is just a single character, this is actually significantly faster, especially for long arrays of strings:

```julia
findall(name -> startswith(name, 'a'), ["aa", "ab", "ca"])

```

That is, use a char, `'a'`, instead of a string, `"a"`.

---

<div class="post-metadata">

**Author:** ![rssdev10](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@rssdev10](https://discourse.julialang.org/u/rssdev10)\
**Post date:** [January 12, 2019, 4:46pm UTC](https://discourse.julialang.org/t/filter-by-array-of-tuples/19534/12 "2019-01-12T16:46:48Z")

</div>

> If your matching string is just a single character,

Thanks. In my actual case it looks like:

```julia
function get_indices_for_prefix(df::DataFrame, prefix::String)
    findall(name -> startswith(string(name), prefix), names(df))
end

```
