octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ismember bugs


From: Søren Hauberg
Subject: ismember bugs
Date: Sat, 11 Aug 2007 01:44:41 +0200
User-agent: Thunderbird 1.5.0.12 (X11/20070604)

Hi,
I just had a look at the 'ismember' bugs (to see the bugs, run 'test ismember'). I find the 'ismember' code fairly hard to read, so I rewrote the function from scratch. I've attached the result. Assuming the 'cellstr' bug that I just reported to the bugs-list is fixed this implementation fixes the bugs. The downside is that my new implementation is quite a bit more slow (too slow). It depends on the 'cellfun' function, which then is the slow part. I don't consider this an alternative to the current implementation, but I'm posting the implementation here in case somebody wants to see the code.

Søren
## Copyright (C) 2007 Soren Hauberg
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, write to the Free
## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301, USA.

## -*- texinfo -*-
## @deftypefn {Function File} address@hidden, @var{idx}] = ismember (@var{A}, 
@var{S})
## Return a matrix the same shape as @var{A} which has @code{true} if
## @code{A(i,j)} is in @var{S} or @code{false} if it isn't.
## @seealso{unique, union, intersection, setxor, setdiff}
## @end deftypefn

function [bool, idx] = ismember (a, S, r)
# XXX: We need to support the 'rows' argument as well.

  if (nargin != 2 && nargin != 3)
    print_usage ();
  endif
  
  ## Check for 'rows' argument
  use_rows = false;
  if (nargin == 3 && strcmp(r, "rows"))
    warning("ismember: ignoring third argument (FIX ME!)");
    use_rows = true;
  endif
  
  ## Convert char matrices to cell arrays
  if (ischar(a))
    a = cellstr(a);
  endif
  if (ischar(S))
    S = cellstr(S);
  endif
  
  ## Input checking (this check is for matlab compatibility)
  if ( !isa(a, class(S)) )
    error("ismember: both input arguments must be the same type");
  endif
  
  ## Take action depending on the type of 'a' and 'S'
  if (isempty(a) || isempty(S))
    idx = zeros(size(a));
  elseif ( iscellstr(a) && iscellstr(S) )
    idx = cellstr_ismember(a(:)', S(:)');
  elseif (ismatrix(a) && ismatrix(S))
    idx = vector_ismember(a(:)', S(:)');
  else
    error("ismember: input must be either matrices or cell arrays of strings");
  endif
  
  ## Reshape output
  idx = reshape(idx, size(a));  
  bool = (idx > 0);
endfunction

## Implementation for 'a' and 'S' being cell arrays of strings
function idx = cellstr_ismember(a, S)
  # 'f(x)' is like 'find(strcmp(x,S),1)', except it returns 0 when no match is 
found
  f = @(x) max(strcmp(x, S).*(1:length(S))); 
  idx = cellfun(f, a);
endfunction

## Implementation for 'a' and 'S' being vectors
function idx = vector_ismember(a, S)
  # 'f(x)' is like 'find(strcmp(x,S),1)', except it returns 0 when no match is 
found
  f = @(x) max(strcmp(x, S).*(1:length(S))); 
  idx = arrayfun(f, a);
endfunction

%!assert (ismember ({''}, {'abc', 'def'}), false);
%!assert (ismember ('abc', {'abc', 'def'}), true);
%!assert (isempty (ismember ([], [1, 2])), true);
%!xtest assert (ismember ('', {'abc', 'def'}), false);
%!xtest fail ('ismember ([], {1, 2})', 'error:.*');
%!fail ('ismember ({[]}, {1, 2})', 'error:.*');
%!assert (ismember ({'foo', 'bar'}, {'foobar'}), logical ([0, 0]))
%!assert (ismember ({'foo'}, {'foobar'}), false)
%!assert (ismember ({'bar'}, {'foobar'}), false)
%!assert (ismember ({'bar'}, {'foobar', 'bar'}), true)
%!assert (ismember ({'foo', 'bar'}, {'foobar', 'bar'}), logical ([0, 1]))
%!assert (ismember ({'xfb', 'f', 'b'}, {'fb', 'b'}), logical ([0, 0, 1]))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]