Skipnothing is missing

This is more of a feature request: skipmissing is useful, as would be skipnothing, if it existed. I know it’s easy to filter the nothing values away, but it’s also nice to drop the Union element type, as is achieved with collect(skipmissing(arr)).

I could make a PR for this, but the code would be almost identical to that underlying skipmissing.

1 Like

I think the intention is to make missing stand for missing values, which propagate kind of semi-automatically when appropriate, and nothing an indicator of situations that there should be a value but there isn’t one and the caller should take explicit action to deal with the situation.

So I am not sure that skipnothing is that useful. In any case, you have

filter(!isnothing, ...)

which is not much longer.

See https://docs.julialang.org/en/v1/manual/faq/#faq-nothing-1

7 Likes

The main distinction I can see between filtering with filter(!ismissing, ...) and collect(skipmissing(...)) is that the resulting collection no longer has element type Union{Missing, ...}. I do not know of a similarly terse way to drop the Union element type for Nothings, when dropping the nothings in a collection, which is an explicit action to deal with the situation.

Try

[x for x in xs if !isnothing(x)]
1 Like

isnothing is not a function, but otherwise this seems like a good alternative: [x for x in xs if x != nothing].

Of course, you could do the same to remove missing values from an iterable, and yet skipmissing exists as a convenient utility function. I still don’t see any difference in utility between skipmissing, and a potential skipnothing function. From the documentation, it seems like skipmissing is motivated to ease reducing iterables containing missing values without getting a missing result. The same problem exists when reducing iterables containing nothing values, except that the reduction would most likely error instead of producing a nothing result.

Anyway, this is just a suggestion. I personally have to deal with nothing values far more than I have to deal with missing values, and I’ve often thought that skipnothing would be useful.

Sorry, working on master. See

You could define it as a function then in your own code.

1 Like

I do have it in my own code. I just think it would be a useful utility for others.

Another difference is that Julia can’t infer that element type of that array comprehension:

julia> a = [1, nothing];
julia> function simple_skipnothing(itr)
       [x for x in itr if x != nothing]
       end
simple_skipnothing (generic function with 1 method)
julia> @code_warntype simple_skipnothing(a)
Variables:
  #self# <optimized out>
  itr::Array{Any,1}
  #5 <optimized out>
  #6 <optimized out>
  isz <optimized out>
  et <optimized out>
  v1 <optimized out>
  st <optimized out>
  #temp#@_9 <optimized out>
  #temp#@_10::Array{_,1} where _

Body:
  begin 
      SSAValue(3) = $(Expr(:new, Base.Iterators.Filter{##6#8,Array{Any,1}}, :($(QuoteNode(#6))), :(itr)))
      SSAValue(4) = $(Expr(:new, Base.Generator{Base.Iterators.Filter{##6#8,Array{Any,1}},##5#7}, :($(QuoteNode(#5))), SSAValue(3)))
      $(Expr(:inbounds, false))
      # meta: location array.jl collect 464
      #temp#@_10::Array{_,1} where _ = $(Expr(:invoke, MethodInstance for grow_to!(::Array{Any,1}, ::Base.Generator{Base.Iterators.Filter{##6#8,Array{Any,1}},##5#7}), :(Base.grow_to!), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0))), SSAValue(4)))
      goto 8 # line 471:
      8: 
      # meta: pop location
      $(Expr(:inbounds, :pop))
      return #temp#@_10::Array{_,1} where _
  end::Array{_,1} where _

This works very well when x is a Vector, however in case x is an Array the resulting is a Vector. Is there a way to do it dimension-wise and keep the shape of Array?

There’s no way to know if each dimensional slice will contain the same number of nothings, but you can filter each slice and then concatenate the equal-length slices, e.g.

julia> v = [nothing 1 0
           0 nothing 1
           1 0 nothing]
3×3 Matrix{Union{Nothing, Int64}}:
  nothing  1         0
 0          nothing  1
 1         0          nothing

julia> reduce(hcat, filter.(!isnothing, eachcol(v)))
2×3 Matrix{Union{Nothing, Int64}}:
 0  1  0
 1  0  1