Filter multi-dimensional array

M

mouac01

I have this multi-dimensional array:

var list = [["a","1"],["a","2"],["b","1"],["b","2"]]

I need a filter function that I can pass the search index and value:

list.filter(0,"a") returns [["a","1"],["a","2"]]

and

list.filter(1,"1") returns [["a","1"],["b","1"]]

-----------

The only thing I found is the filter function below but I'm not sure
how to implement it for multi-dimensional arrays. Thanks....


if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/) {
var len = this.length;
if (typeof fun != "function") throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i=0;i<len;i++) {
if (i in this) {
var val = this;
if (fun.call(thisp, val, i, this)) res.push(val);
}
}
return res;
}
}
 
T

Thomas 'PointedEars' Lahn

I have this multi-dimensional array:

var list = [["a","1"],["a","2"],["b","1"],["b","2"]]

I need a filter function that I can pass the search index and value:

list.filter(0,"a") returns [["a","1"],["a","2"]]

and

list.filter(1,"1") returns [["a","1"],["b","1"]]

-----------

The only thing I found is the filter function below but I'm not sure
how to implement it for multi-dimensional arrays. Thanks....
[...]

function myFilter(a, i, v)
{
var result = a.filter(function(e) {
return e === v;
});

/* break possible circular reference */
i = v = null;

return result;
}

var filteredArray = myFilter(list, 0, "a");


Next time, please show some more initiative and post about the things you
think you have understood. Show what you have tried in following that
assumption, so that you can be corrected where necessary, and everyone can
benefit from your learning experience.

<http://jibbering.com/faq/#posting>
<http://www.catb.org/~esr/faqs/smart-questions.html>


PointedEars
 
T

Thomas 'PointedEars' Lahn

Stefan said:
I have this multi-dimensional array:

var list = [["a","1"],["a","2"],["b","1"],["b","2"]]

I need a filter function that I can pass the search index and value:

list.filter(0,"a") returns [["a","1"],["a","2"]]

and

list.filter(1,"1") returns [["a","1"],["b","1"]]
The only thing I found is the filter function below but I'm not sure
how to implement it for multi-dimensional arrays. Thanks....

The filter() method of the Array prototype doesn't accept the arguments
you need,

Just not directly, see my other follow-up.
and it's not available in all implementations (browsers) yet.

Probably that's why there is

if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/) {

....

One should use isMethod(), though, instead of the type-converting test.
Some people don't like to extend the built-in Array prototype, but it's
your call.

It is not just a matter of preference; one has to take extra care with
for-in iteration and the `in' operator if prototypes of built-in objects are
augmented as those user-defined properties are enumerable and show up with
the inheriting instances then.


PointedEars
 
R

Richard Cornford

On Oct 1, 1:15 pm, Stefan Weiss wrote:
for .. in should not be used to iterate over array elements.

That is far too general a statement.
It kind of
works in all existing implementations (that I know of),

By which you mean it does work as specified in existing
implementations (or at least those recent enough to be of interest, as
Netscape 4 had some aberrant behaviour with for-on use on arrays).
but there's no
guarantee for any specific iteration order.

That is true of for-in applied to any object, so if order matters for-
in is the wrong approach (unless you can guarantee the environment,
and that it will be consistent and stable over time in this regard).
If you do use it (for example, with sparse arrays), you'll have
to filter the keys anyway, because even if Array.prototype hasn't
been modified, the array itself could have additional non-element
properties.

The implication that javascript is a random mush of behaviour where
things like arrays may unexpectedly gain properties at any time is
ludicrous. It is computer code, using relentless mechanical logic do
precisely what it is told to do. If - Array.prototype - is modified
then that is because code was executed that modified it, and if an
array instance gains additional properties that is also because code
was executed that added those properties. So we can know, with
certainty, when and which considerations pertain to making decisions
about using things like for-in, and so recognise situations where it
is absolutely safe and sensible to do so. Similarly, if a page has
imported a library that does modify - Array.prorotype - you can be
certain that if you are going to use for-in then filtering the keys is
a necessity.

There may also be situations where what you know with certainty is
that cannot rely on an environment, if, for example, writing code that
will be employed in an advert, and so may end up on any page with any
javascript running around it, or for a page that displays such
advertisings where you could not be certain that the advertising code
was not making such modifications.

There is no need for knee-jerk blanket injunctions here, just an
understanding of the consequences that follow from the context.

Richard.
 
T

Thomas 'PointedEars' Lahn

Stefan said:
I know, but your other solution would also require the retro-fitted
filter() method, unless the target platform is known.

Your mostly correct explanation notwithstanding, using the filter() method
was exactly what the OP was asking about. In fact, if code reuse is not an
issue, this could be:

var filteredArray = list.filter((function(i, v) {
return function(e) {
var res = (e === v);
i = v = null;
return res;
};
)(1, "a"));

Isn't that a bit more elegant than pushing things around?
for .. in should not be used to iterate over array elements.
NAK

It kind of works in all existing implementations (that I know of),
^^^^^^^^^^^^^
Sounds like FUD. It works in all compliant ECMAScript implementations,
and IIRC none has been spotted to date that is not compliant there.
but there's no guarantee for any specific iteration order.

I know. Nobody implied that, and order is not always important.
If you do use it (for example, with sparse arrays),

Especially with sparse arrays for-in is useful. It does not necessarily
observe order, but it accesses only existing enumerable properties.
you'll have to filter the keys anyway, because even if Array.prototype
hasn't been modified, the array itself could have additional non-element
properties.

True. If one deliberately breaks their own for-in iteration by augmenting
the Array instance they are about to iterate over this way, they deserve
what they get.


PointedEars
 
R

Richard Cornford

Stefan Weiss wrote:

^^^^^^^^^^^^^
Sounds like FUD.

It does.
It works in all compliant ECMAScript implementations,
and IIRC none has been spotted to date that is not
compliant there.
<snip>

Netscape 4 had an issue where if you did - for( prop in arry ) ... -
on an array then - prop - would have numeric values instead of the
ECMAScript specified string values. Usually not an issue but it did
come up a few times on the group as error-causing. Not that anyone
will be worrying about minor faults in Netscape 4 at this stage.

Richard.
 
T

Thomas 'PointedEars' Lahn

Stefan said:
The "kind of works" part was not intended to mean that for..in would
fail to find all elements, but that the iteration order is not specified
and that it can return properties which aren't array indices.

But so far that does not serve as a good general reason for not using it,
because the "properties that aren't array indices" would have to be added
either by the same person that does the iteration or a person that is
incompetent enough to use code that augments Object.prototype or
Array.prototype *and* use for-in on Array instances without precautions.

IOW: That for-in iteration of unaugmented Array instances that inherit from
unaugmented objects accesses only indexed properties is supported both by
the Specification and all observations about implementations. It is not
logical to assume that an otherwise working implementation would do anything
different here, and it is FUD to imply that therefore for-in should not be
used there.
All of which I've mentioned later, so that makes the my "kind of" remark
redundant. It was a stylistic misstep, not FUD.

In that case I daresay you are still off track.
The implication that javascript is a random mush of behaviour where
things like arrays may unexpectedly gain properties at any time is
ludicrous. It is computer code, using relentless mechanical logic do
precisely what it is told to do. If - Array.prototype - is modified
[snip]

for..in is only equivalent to for(;;) for element iteration, if [...]

That is where you are still thinking in the wrong direction. Nobody even
implied that it would be equivalent.


PointedEars
 
R

Richard Cornford

The "kind of works" part was not intended to mean that for..in
would fail to find all elements, but that the iteration order
is not specified and that it can return properties which aren't
array indices. All of which I've mentioned later, so that makes
the my "kind of" remark redundant. It was a stylistic misstep,
not FUD.
The implication that javascript is a random mush of behaviour
where things like arrays may unexpectedly gain properties at
any time is ludicrous. It is computer code, using relentless
mechanical logic do precisely what it is told to do. If -
Array.prototype - is modified

[snip]

for..in is only equivalent to for(;;) for element iteration, if

You have just become the first person to mention equivalence in this
thread, so it is unlikely that not being equivalent will be pertinent
to anything that has previously been said.
a) you can be sure that nothing on the page has augmented the
Array.prototype, and

b) you can be sure that the array passed to your function contains
no enumerable properties except the array indices, and

c) you want to iterate over all elements, no lower/upper boundaries,
no skipping, no jumping, and

d1) you do not require the elements to be processed in any specific
order, or

d2) you trust the for..in implementation to return sorted indices

If all that holds true, for..in is fine.

You mentioned the possibility of filtering the property names/value,
and if the appropriate filtering is done then your a and b may not be
significant. But still, there is no need for equivalence in order to
dispute your "for .. in should not be used to iterate over array
elements" so supposed pre-conditions for equivalence don't mean much.
(a) alone excludes most
third-party library writers and many library users,

Are you saying that most third-party libraries modify -
Array.prototype - ?

In any event, the users of third-party libraries know that they are
doing that, and should be aware of how that action impacts on what
they can/should do it their own code. (Granted, a significant
proportion of the users of 'third-party' libraries don't have any clue
about what they are doing at all, but they probably don't know for-in
does and wouldn't understand your injunction anyway.)
which is a
significant part of all deployed scripts today. I would also hazard
a guess that ordering is more often required than not.

Maybe, but when it is required it can be observed to be required, and
when it is not that can also be observed. There is no need to never
use an unordered iteration just because there may be circumstances
where only ordered will do.
I've mentioned
sparse arrays as an exception where for..in is usually the better
choice.

You mentioned sparse arrays, but not as an exception to your
injunction.
Note that I didn't say "can not be used", but "should not". As a
best-practices recommendation for defensive programming,

Defensive or paranoid?
I would still stand by that. With arrays, for..in doesn't offer
any real benefit over for(;;), apart from being a few characters
shorter, and has all the drawbacks I mentioned above. If
developers get into the habit of preferring for(;;), they'll
be just as productive, and they're free to modify Array.prototype,
which can lead to more expressive code (IMO).

So there are reasons for a preference, not an injunction.

Richard.
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
Stefan said:
Thomas 'PointedEars' Lahn wrote:
Stefan Weiss wrote:
Some people don't like to extend the built-in Array prototype, but it's
your call.
It is not just a matter of preference; one has to take extra care with
for-in iteration and the `in' operator if prototypes of built-in objects are
augmented as those user-defined properties are enumerable and show up with
the inheriting instances then.
for .. in should not be used to iterate over array elements.
[...]
If you do use it (for example, with sparse arrays),
Especially with sparse arrays for-in is useful. It does not necessarily
observe order, but it accesses only existing enumerable properties.

If you have a sparse array, shouldn't you really be using an Object
object not an Array object?

No. To begin with, a "plain" Object instance does not provide built-in
Array methods and properties.
It's more efficient
Depends.

and doesn't require to tackle with `Array.prototype.*` methods filtering.

There is not much of a difference with *incompetent* prototype augmentation.
Object.prototype can be and has been augmented as well. (No offense meant.)


PointedEars
 
M

mouac01

I have this multi-dimensional array:
var list = [["a","1"],["a","2"],["b","1"],["b","2"]]
I need a filter function that I can pass the search index and value:
list.filter(0,"a") returns [["a","1"],["a","2"]]

list.filter(1,"1") returns [["a","1"],["b","1"]]
The only thing I found is the filter function below but I'm not sure
how to implement it for multi-dimensional arrays.  Thanks....

The filter() method of the Array prototype doesn't accept the arguments
you need, and it's not available in all implementations (browsers) yet.
You could write a custom filter() function:

  function filter (arr, idx, val) {
      var res = [],
          i = 0,
          len = arr.length;
      for (; i < len; ++i) {
          if (arr[idx] === val) {
              res.push(arr);
          }
      }
      return res;
  }

  var list = [["a","1"],["a","2"],["b","1"],["b","2"]];
  var filteredList1 = filter(list, 0, "a");
  var filteredList2 = filter(list, 1, "1");

If you _really_ want to use it as an array method, you'd have to call it
something else, or you'll overwrite the (possibly existing) filter() method:

  Array.prototype.myFilter = function (idx, val) {
      var res = [],
          i = 0,
          len = this.length;
      for (; i < len; ++i) {
          if (this[idx] === val) {
              res.push(this);
          }
      }
      return res;
  };

  var filteredList1 = list.myFilter(0, "a");
  var filteredList2 = list.myFilter(1, "1");

Some people don't like to extend the built-in Array prototype, but it's
your call.

cheers,
stefan


Thanks, Stefan. I like your approach.
 
T

Thomas 'PointedEars' Lahn

Stefan said:
It seems that I've caused great confusion with my "kind of works" remark.
My apologies for that. Anyway, given all of the conditions stated in your
previous paragraph, then yes, for(in) "works". It won't support some
features like a guaranteed order, skipping the next 10 iterations, or
repeating the previous one, but it "works" for the given premises.
Unfortunately, those premises are far from universal (for example, a user
may decide to include a nifty LightBox on their page, that might just
happen), and then their for(in) won't work so well anymore.

But don't you see that "to include a nifty Lightbox" would be the very cause
of the problem?
You may call those users clueless,

Yes, most certainly I do.
and you may say that I'm spreading FUD about the dangers of using
unfiltered for(in),

Yes, I do, if you are using badly written libraries as a justification for
not using for-in.
but actually I'm fine with that.

That's too bad.
People deserve a healthy dose of FUD about for(in), _especially_ if they
don't know what they're doing.

But you are telling them not to use an otherwise working language feature
instead of telling them that they should not use badly written libraries.
Isn't that the *wrong* message, a Bad Thing? Most of us are here to help
*improve* overall code quality, not to teach others how to jump through
hoops script-kiddies have set up, and not to keep the current (bad) status quo.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Stefan said:
for..in is only equivalent to for(;;) for element iteration, if
[snip]
You have just become the first person to mention equivalence in this
thread, so it is unlikely that not being equivalent will be pertinent
to anything that has previously been said.

Strawman.

JFTR: No, a straw man argument¹ is something else.

You said:

,-<|
| for..in is only equivalent to for(;;) for element iteration, if [...]

in reply to Richard's

,-<|
| The implication that javascript is a random mush of behaviour where
| things like arrays may unexpectedly gain properties at any time is
| ludicrous. It is computer code, using relentless mechanical logic do
| precisely what it is told to do. If - Array.prototype - is modified [...]

(Care to explain what your answer has to do with what you replied to?)

So there is no way to define Richard's stating the mere fact as a
misinterpretation of your position (and also no way to define it as an
interpretation of your position). Richard is correct; nobody else but you
said or implied equivalence before, so your introducing it there does not
bear any meaning to what was argued before.
I never said or implied that anybody in this thread has talked
about equivalence before.

True, but *you* talked about it, and that's the problem. In fact, I daresay
that was a red herring fallacy² on your part.


HTH

PointedEars
___________
¹ <http://en.wikipedia.org/wiki/Straw_man>
² <http://en.wikipedia.org/wiki/Red_herring_(logical_fallacy)#Red_herring>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top