PDA

View Full Version : Working With Arrays



techno_race
08-18-2008, 05:27 PM
I n̶e̶e̶d̶ want help. :p
I am working on a [rather complicated] JavaScript.
I need help with the following stages:
STAGE 4
Divide characters in a string into array values.
For example, if I have (this is done with PHP):

var word1 = "animal";
then it would make:

var array1 = new Array('a','n','i','m','a','l');

STAGE 5
Do something for all the values.
For example:

if (array1[0] == array2[0]) {
//do something
}
if (array1[1] == array2[1]) {
//do the same thing
}
What I am asking is if it is possible to repeat this same thing for array.length.
The arrays will be the same length.

Another thing is if it is possible to just see if there are two values in the arrays that are the same and return them as variables, like:

var inarray1 = 2;
var inarray2 = 6;
if

var array1 = new Array('a', 'b', 'c', 'd');
var array2 = new Array('x', 'f', 's', 'y', 'l', 'w', 'q', 'c', 'i');
Note that if this occurs multiple times, I want it to use the first time.

Twey
08-18-2008, 06:44 PM
The first is String.prototype.split():
var array1 = word1.split("");The third:
var Functional = {
map: function(f, a) {
for (var i = 0, n = a.length, r = []; i < n; ++i)
r[i] = f(a[i], i);

return r;
},

filter: function(f, a) {
for (var i = 0, r = []; i < a.length; ++i)
if (f(a[i], i))
r[r.length] = a[i];

return r;
},

compose: function(/* f1 [, f2 [, ... [, fn]]] */) {
var fs = Array.prototype.slice.call(arguments);

return function() {
var args = Array.prototype.slice.call(arguments);

for (var i = fs.length - 1; i >= 0; --i)
args.unshift(fs[i].apply(this, args));

return args[0];
};
},

flip: function(f) {
return function(a, b) {
return f.call(this, b, a);
};
},

curry: function(f, l, a) {
l = (typeof l === "number" ? l : (f.length || 0));
a = a || [];

return function() {
var m = a.concat(Array.prototype.slice.call(arguments));
return m.length < l ? Functional.curry(f, l, m) : f.apply(this, m);
};
},

Operators: {
lookup: function(a, i) {
return a[i];
},

equals: function(a, b) {
return a === b;
}
}
};

var parallels = (function(F, O) {
return function(a1, a2) {
return F.filter(F.compose(O.equals, F.flip(F.curry(O.lookup, 2)(a2))), a1);
};
})(Functional, Functional.Operators);And the second, using the same Functional object as above:
function doForAllParallels(a1, a2, f) {
return Functional.map(function(v, k) {
if (a2[k] === v)
return f(v, k);
}, a1);
}

Trinithis
08-18-2008, 08:33 PM
I have a couple questions, Twey.

In flip you have f.call(this, b, a); instead of f(b, a); Is that so it is compatable with method calls?

I'm curious about your compose function. Even though I understand what it does, it seems a little unconventional to keep a history of old arguments. Why do you do that? I see the use of it in your parallels function to pass both args to a binary function, but in general, is your compose function more useful than an ordinary one?

I personally define compose as


Function.prototype.o = function(g) {
var f = this;
return function() {
return f(g.apply(null, arguments));
};
};

// eg: var k = f. o (g). o (h);


Also, how about


function doForAllParallels(f, a1, a2) {
return Functional.map(f, parallels(a1, a2));
}

// var doForAllParallels = (function(F) {
// return F.compose( F.curry(F.map)(f), parallels );
// })(Functional);


PS: It would be cooler if all the functions in Functional were curried to begin with!

Edit: I'm not sure, but I think var fs = Array.prototype.slice.call(arguments); can be simplified to var fs = arguments;

Twey
08-18-2008, 08:54 PM
In flip you have f.call(this, b, a); instead of f(b, a); Is that so it is compatable with method calls?More or less. It's so that if somehow a context gets passed to the wrapper function, it will be passed through transparently, as would be expected, rather than being lost, which is what would otherwise happen.

This isn't actually the version of flip() in my toolkit, I revised it but the revision isn't beneficial here: it's now:
reorder: function(f, ord) {
return function() {
return f.apply(this, F.map(F.curry(O.lookup, 2, [arguments]), ord));
};
},

flip: function(f) {
return F.reorder(f, [1, 0]);
},
I'm curious about your compose function. Even though I understand what it does, it seems a little unconventional to keep a history of old arguments.Unconventional only from a Haskell perspective. In JS, I discovered as I was writing this, things are not quite so simple, due to every function taking a variable number of arguments. In addition, this is quite a non-Haskelly solution: in Haskell it would probably be preferable to do something like this:
parallels :: (Eq a) => [a] -> [a] -> [a]
parallels [] _ = []
parallels _ [] = []
parallels (x:xs) (y:ys) =
if x == y then
x : (parallels xs ys)
else
parallels xs ys(that is to say,
function parallels(xs, ys) {
if (!xs.length || !ys.length)
return [];

if (x === y)
return [xs[0]].concat(parallels(xs.slice(1), ys.slice(1)));

return parallels(xs.slice(1), ys.slice(1));
}) ... but recursion is generally discouraged in JS, since there's no optimisation for it and a fairly small stack.
Also, how about [implementing doForAllParallels in terms of map?]Doesn't preserve keys, which was an implicit requirement. I almost wrote a filterStatic() and mapStatic() in which to implement it, but didn't in the end.
PS: It would be cooler if all the functions in Functional were curried to begin with!Considered it already, but rejected on the grounds of performance.

Trinithis
08-18-2008, 09:04 PM
I'm guessing xxxStatic is like its xxx variant but throws Maybe (or something similar) into the mixture?

Twey
08-18-2008, 09:06 PM
Well, for a given definition of Maybe:
function maybe(val, isNothing) {
return isNothing ? undefined : val;
}:)

Trinithis
08-18-2008, 09:09 PM
I wrote this a while ago:

function Maybe(val, isJust) {
this.fromJust = val;
this.isJust = isJust;
}

Maybe.unit = Just;

Maybe.prototype = {
bind: function(f) {
return this.isJust
? f(this.fromJust)
: Nothing
;
},
then: function(m) {
return this.bind(function() {
return m;
});
},
toString: function() {
return "[object Maybe]";
}
};

function Just(val) {
return new Maybe(val, true);
}

var Nothing = new Maybe(undefined, false);

As of late, I've been trying to figure out a user-friendly way to implement type classes in such a way that types can be inferered along the way with a little help. So far, all my ideas have turned out to be somewhat painful. But if I succeed, then I can truly implement a monad typeclass, which would be cool.

Twey
08-18-2008, 09:46 PM
Not bad, not bad. I would maybe do it a little differently if we're going for elegance rather than efficiency:
var Maybe = (function() {
function Maybe(val) {
if (val === undefined)
return Nothing;
else
return Just(val);
}

function Nothing() {
return Nothing;
}

Nothing.toString = function toString() {
return "Nothing";
};

Nothing.bind = function bind(f) {
return Nothing;
};

Nothing.then = function then(f) {
return Nothing;
};

function Just(val) {
function Just() {
return Just;
}

Just.fromJust = function fromJust() {
return val;
};

Just.toString = function toString() {
return "Just " + val;
};

Just.bind = function bind(f) {
return _Just(f(val));
};

Just.then = function then(f) {
return _Just(f());
};

return Just;
}

var _Just = Just;

return Maybe;
})();Chris / chrisdone / la .xris. wrote a somewhat clumsy implementation of State in JS: http://chrisdone.com/stuff/javascript-state-monad.js.html.

Trinithis
08-18-2008, 10:00 PM
Interesting take. There's one thing I like in mine over yours . . . Maybe governs bind instead of the individual constructors. Also, yours doesn't allow a Just undefined.

Never knew the following syntax was legal:


Nothing.bind = function bind(f) {
return Nothing;
};


I saw that State implentation before when googling monads in javascript. I didn't like it.

Twey
08-18-2008, 10:22 PM
There's one thing I like in mine over yours . . . Maybe governs bind instead of the individual constructors.That's one of the things I disliked :) It seems neater to split it up. Consider the Haskell implementation (paraphrased, sorry):
Nothing >>= _ = Nothing
(Just x) >>= f = f xClearly separate.
Never knew the following syntax was legal:I have an inhibition against using it. I very vaguely remember seeing somewhere that it was very slow. However, as the disclaimer says, it's elegance not efficiency, so I thought I may as well.
Also, yours doesn't allow a Just undefined.Well, that's easy enough to solve:
var Maybe = (function() {
function Maybe(val) {
if (!arguments.length)
return Nothing;
else
return Just(val);
}

function Nothing() {
return Nothing;
}

Nothing.toString = function toString() {
return "Nothing";
};

Nothing.bind = function bind(f) {
return Nothing;
};

Nothing.then = function then(f) {
return Nothing;
};

function Just(val) {
function Just() {
return Just;
}

Just.fromJust = function fromJust() {
return val;
};

Just.toString = function toString() {
return "Just " + val;
};

Just.bind = function bind(f) {
return _Just(f(val));
};

Just.then = function then(f) {
return _Just(f());
};

return Just;
}

var _Just = Just;

return Maybe;
})();To create a Nothing:
Maybe()To create a Just undefined:
Maybe(undefined)

Twey
08-19-2008, 11:06 PM
Actually, I just realised that automatically wrapping the result is bad, since it means I can't choose to return a Nothing.
var Maybe = (function() {
function Maybe(val) {
if (!arguments.length)
return Nothing;
else
return Just(val);
}

function Nothing() {
return Nothing;
}

Nothing.toString = function toString() {
return "Nothing";
};

Nothing.bind = function bind(f) {
return Nothing;
};

Nothing.then = function then(f) {
return Nothing;
};

function Just(val) {
function Just() {
return Just;
}

Just.fromJust = function fromJust() {
return val;
};

Just.toString = function toString() {
return "Just " + val;
};

Just.bind = function bind(f) {
return f(val);
};

Just.then = function then(f) {
return f();
};

return Just;
}

return Maybe;
})();Anyway, we've dragged this poor thread far off-topic :)

techno_race
08-20-2008, 02:50 AM
(More or less) Thanks for the replies.

Twey, your post (#2) didn't make much sense. Please explain how to use these and which things they do.

Twey
08-20-2008, 02:53 AM
By '(#2)' do you mean the second post in the thread, or my second post (in reply to Trinithis)?

techno_race
08-20-2008, 03:29 AM
The second post in the thread.

Twey
08-20-2008, 04:52 AM
With comments:
// Return an array of all characters in the string `word'
word.split("");
var Functional = {
// Apply a function to each item in an array and return an
// array of the results.
map: function(f, a) {
for (var i = 0, n = a.length, r = []; i < n; ++i)
r[i] = f(a[i], i);

return r;
},

// Apply a function to each item of an array and remove
// the item if the result is falsy.
filter: function(f, a) {
for (var i = 0, r = []; i < a.length; ++i)
if (f(a[i], i))
r[r.length] = a[i];

return r;
},

// Combine functions into one.
// A generalisation to multiple arguments of function
// compose(a, b) { return function(c) { return a(b(c)); }; }
compose: function(/* f1 [, f2 [, ... [, fn]]] */) {
var fs = Array.prototype.slice.call(arguments);

return function() {
var args = Array.prototype.slice.call(arguments);

for (var i = fs.length - 1; i >= 0; --i)
args.unshift(fs[i].apply(this, args));

return args[0];
};
},

// Reverse the order of arguments of a function.
flip: function(f) {
return function(a, b) {
return f.call(this, b, a);
};
},

// Curry a function (I wrote a thread on this, search)
curry: function(f, l, a) {
l = (typeof l === "number" ? l : (f.length || 0));
a = a || [];

return function() {
var m = a.concat(Array.prototype.slice.call(arguments));
return m.length < l ? Functional.curry(f, l, m) : f.apply(this, m);
};
},

// Simple functions to replace operators (because we can't
// pass operators as arguments).
Operators: {
// Lookup a key on an object.
lookup: function(a, i) {
return a[i];
},

// Check if two values are equal.
equals: function(a, b) {
return a === b;
}
}
};

// Outer function exists just to provide shorter names.
var parallels = (function(F, O) {
return function(a1, a2) {
// For each item in the list a1, check whether it should
// be in the new list by testing whether the item under
// the same key in the list a2 is the same as the current
// item.
return F.filter(F.compose(O.equals, F.flip(F.curry(O.lookup, 2)(a2))), a1);
};
})(Functional, Functional.Operators);
// Just apply the function f for all items in a1 that are
// the same as the item in the same position in a2.
function doForAllParallels(a1, a2, f) {
return Functional.map(function(v, k) {
if (a2[k] === v)
return f(v, k);
}, a1);
}

techno_race
08-20-2008, 04:57 PM
possible to just see if there are two values in the arrays that are the same and return them as variables, like:

var inarray1 = 2;
var inarray2 = 6;
if
var array1 = new Array('a', 'b', 'c', 'd');
var array2 = new Array('x', 'f', 's', 'y', 'l', 'w', 'q', 'c', 'i');

Note that if this occurs multiple times, I want it to use the first time.
Is it possible?

Trinithis
08-20-2008, 06:32 PM
function findMatching(xs, ys) {
for(var i = 0; i < xs.length; ++i)
for(var j = 0; j < ys.length; ++j)
if(xs[i] === ys[j])
return [i, j];
return [-1, -1];
}

alert(findMatching(
['a', 'b', 'c', 'd']
, ['x', 'f', 's', 'y', 'l', 'w', 'q', 'c', 'i']
));



Here's a link to something a little more general:
http://www.codingforums.com/showpost.php?p=683246&postcount=15