Skip to main content

News

Topic: Link.js v0.4.2 (Read 95650 times) previous topic - next topic

0 Members and 2 Guests are viewing this topic.
  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #225
Awesome, love the index tracking.  I do remember a few instances where it would have been helpful to know the index into the array, so definitely a good addition.

Fuse is neat as well, although I don't think I have a use case for it yet.  I'm sure I'll find one though!  There have been a lot of features in Link that I thought I would never use and ended up using anyway at some point or another.  For instance, random(), which is awesome for enemy AIs.

Just to be sure, is 0.3.0 code-compatible with 0.2.16?  I want to make sure before I just drop the new version into Specs.  That toArray() bug was a nightmare, don't need more Link glitches showing up tricking me into thinking the problem is on my end. ;)
  • Last Edit: February 17, 2015, 01:12:24 pm by Lord English
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #226

Just to be sure, is 0.3.0 code-compatible with 0.2.16?  I want to make sure before I just drop the new version into Specs.  That toArray() bug was a nightmare, don't need more Link glitches showing up tricking me into thinking the problem is on my end. ;)


Well I try to test it in a browser first. That toArray() bug was really, really weird though. I have so far used it as a drop-in replacement of 0.2.16, it really only adds a new parameter to all function calls so unless you are using that space for something else I'm sure it wouldn't hurt. The only bugs I foresee and hence why it is still in beta, is that I might have not added added the index parameter to the chain somewhere. It really only works if that value can be passed on from item to item. For most cases it is working so I think it's 80%+ good.

Oh, also, the index is not the newly filtered index, so be careful, it still references the original index. It does that since you could pluck, filter, and replace into the same indices you plucked from. Getting the filtered or final index should really only be feasible at the end of the chain, so only after a real toArray(). I'm professionally using this library on a few websites I work on, so it has to work (lol), and I can do data conversion really efficiently with it now (creating a new array and copying over the new values is slower than modifying the existing one as you can imagine, it's also impossible to tell where the final values originally mapped without back-peddling until now).

Edit: As a side note, I even added the standard 'undefined' fix to it, just in case :P
  • Last Edit: February 17, 2015, 02:17:38 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #227
New post, new feature, still v0.3.0:

Code: (javascript) [Select]

var array = [{ a: 1, b: "Hi" }, { a: 2, b: "Hello" }, { a: 3, b: "Bob" }, { a: 4, b: "World" }, { a: 6, b: "skip" }];
console.log(Link(array).pluck("a").filter(even).take(2).unpluck("a").pluck("b").join(" ")); // Hello World


There you go, unpluck. It will remove the need of creating a new link context and prior filters etc. are still honored, so this will result in a speed improvement too.

I also fixed string-based .join() to recognize a default parameter, "" when it is invoked with no parameters. This is the same join that if you pass a function, performs a SQL join, a strange overload but it's semantically sound... I guess.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #228
New popst, two new features, still 0.3.0:

Sum() and Average() have been added. I can't believe these had been missing for as long. :/

They both assume the array is numbers by default, but if you pass into them a string property, it'll attempt to use that inside the parent object. Or you can pass a function to either and resolve it dfrom the item argument:

Three ways of doing the same thing:
Code: (javascript) [Select]

Link([{ a: 45 }, { a: 1 }, { a: 12 }]).sum("a"); // 58
Link([{ a: 45 }, { a: 1 }, { a: 12 }]).sum(function(item) { return item.a; }); // 58
Link([{ a: 45 }, { a: 1 }, { a: 12 }]).pluck("a").sum(); // 58
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • N E O
  • [*][*][*][*][*]
  • Administrator
  • Senior Administrator
Re: Link.js v0.3.0
Reply #229
Sum() and Average() have been added. I can't believe these had been missing for as long. :/


<kidding>I CAN'T BELIEVE YOU'RE STILL MISSING THE REST OF EXCEL'S FUNCTIONS >:(  </kidding>

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #230
Radnen, thought you might like to know this.  In the most recent duktape release's changelog:

Quote
Fix assignment evaluation order issue which affected expressions like "a[ i] = b[i++]" (GH-118)


This verifies that the Link misbehavior under minisphere was indeed a JS engine bug.  Might want to alert the Jurassic devs now! :P
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #231
Feature request (unless this already exists): Function to return index in array of first match, like this:

Code: (javascript) [Select]
this.items = [
{ name: "Party", id: 'party' },
{ name: "Items", id: 'items' }
];
this.selection = Link(this.items).pluck('id').indexOf('items'); // == 1


Or something similar.  I can kind of hack a solution together using .toArray(), but that only gives me the index into the *processed* array, whereas I always want it to index against the input array, even if the query filters stuff out.  Is this possible?
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #232
Did you try that out? It works just fine for me. Are you using v0.3.0?
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #233
Huh. So there is an indexOf method in Link after all.  However:

Code: (javascript) [Select]
var items = [
{ name: "Party", id: 'party' },
{ name: "Items", id: 'items' },
{ name: "Battlers", id: 'battlers' }
];
var index = Link(items).filterBy('id', 'battlers').pluck('id').indexOf('battlers'); // == 0, was expecting 2


Is there any way to get it to always return the index in the original array, or no?
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #234
You could do this:
Code: (javascript) [Select]

var index = Link(items).pluck('id').indexOf('battlers');


If you want to filter for any reason and keep a reference to the original index, there is a way by using the new second argument in link 0.3.0:
Code: (javascript) [Select]

var index = 0;
Link(items).filterBy('id', 'battlers').each(function(item, idx) { if (item.id == 'battlers') index = idx; });
index; // use index from here on out.


Either I need to add a getRealIndex() method (versus the indexOf which gets the post-filtered index) or I research a way to efficiently return early from an each operation.

Then there is the question:
Should indexOf use the post-filtered index or should it grab the original index? I ask because the indexOf operation is fast since I don't have to copy values to a new intermediate array to get the post-filtered index.

It would suck to have to do something like:
Code: (javascript) [Select]

Link(Link(array).filter().toArray()).indexOf();


It's better to:
Code: (javascript) [Select]

Link(array).filter().indexOf();
Link(array).filter().oldIndexOf(); //or whatever I end up calling it


I've always liked the C-style one word naming convention, so I want to avoid an unnecessarily wordy API, even if it describes the action well enough.
  • Last Edit: April 01, 2015, 05:07:35 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #235
Yeah, just a pluck and indexOf will work.  The reason I ask for a version that works even after filtering is mostly hypothetical: suppose you're given a partial chain that already has a few filtering ops attached to it, you can just tack a pluck().indexOf() onto the end of it to still get the original index (assuming it passes the filter anyway).

But yeah, I can see how that might be a performance hit since every link in the chain (...holy crap, the name Link works on so many levels!) will have to track indices anew.  Your choice, just wanted to bring up a potential use case.  For my purposes pluck and indexOf are sufficient.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #236
Actually I'm going to totally redefine the behavior of indexOf. It's always going to use the original array for now on. To get the filtered or final index just pass true to the end of indexOf, like so:

Code: (javascript) [Select]

Link([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).filter(even).indexOf(10, true);// 5


This means removing a feature, indexOf(prop, value). But I think it's okay to remove that feature since you can always use pluck before you call indexOf.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #237
It won't hurt the performance of the other operations if indexOf isn't used will it?  Realistically I don't see indexOf to be a common thing to do with Link, so I'd hate to have something like this bring everything else down.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.3.0
Reply #238
Actually I'm making indexOf faster by doing this. The index is already passed as the second parameter I'll just leverage this free gift.

Since this is lazy execution, indexOf makes the entire thing really fast in fact. Imagine only looking as far as the 4th item (because whatever it is, it happens to be the one that matches). Then imagine having 1 million items in the list. It really only executes the chain 4 times, rather than execute everything then find the the item that matches, even if it's only 4th position.

This is why methods like split, indexOf, take, get, contains, every, and first are very fast, they stop as soon as the predicate is matched, after only having executed the chain until then. And in the case of string split, it doesn't have early termination in native JS.

Edit:
I'm going to scrap what I did to indexOf.


suppose you're given a partial chain that already has a few filtering ops attached to it, you can just tack a pluck().indexOf() onto the end of it to still get the original index (assuming it passes the filter anyway).


It shouldn't work like that. Filter dirties the chain. In practice it makes sense for indexOf to return only the new index after filtration. I was thinking maybe not, but this is a lazy execution environment. There are times can no longer get the original index of an item. After some time that data vanishes further into the chain you go.

Take for instance:
Code: (javascript) [Select]

Link([0, 1, 5, 4]).filter(function(n) { return n > 3; }).skip(1).indexOf(5);
Link([0, 1, 5, 4]).filter(function(n) { return n > 3; }).skip(1).indexOf(5, true);


They both return -1 (does not exist), but shouldn't #2 return 2? Well it would if the combination of the filter and the skip doesn't destroy element 5 from existence. See, it only works to get the item in the original array if it survives the chain of operation. So, it makes sense to use the filtered value because in this case at least it's guaranteed to produce a result in alignment with the data it operates on.

But I do see one use of an unfiltered index version of indexOf. There is a speed increase. If you filter out even numbers and you know the item is odd, but you want the original index, and the item is somewhere within the first half of the list. We can filter out the numbers we don't need to check, get to the odd number faster, and then get the index, returning the original index rather than the filtered index. But it might almost be faster to just get the index of the odd number anyways, I'd only see this as a speed increase if you work with millions of numbers. Filter is fast, but indexOf is faster.
  • Last Edit: April 02, 2015, 01:20:49 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.3.0
Reply #239

Edit:
I'm going to scrap what I did to indexOf.


suppose you're given a partial chain that already has a few filtering ops attached to it, you can just tack a pluck().indexOf() onto the end of it to still get the original index (assuming it passes the filter anyway).


It shouldn't work like that. Filter dirties the chain. In practice it makes sense for indexOf to return only the new index after filtration. I was thinking maybe not, but this is a lazy execution environment. There are times can no longer get the original index of an item. After some time that data vanishes further into the chain you go.

Take for instance:
Code: (javascript) [Select]

Link([0, 1, 5, 4]).filter(function(n) { return n > 3; }).skip(1).indexOf(5);
Link([0, 1, 5, 4]).filter(function(n) { return n > 3; }).skip(1).indexOf(5, true);


They both return -1 (does not exist), but shouldn't #2 return 2? Well it would if the combination of the filter and the skip doesn't destroy element 5 from existence. See, it only works to get the item in the original array if it survives the chain of operation. So, it makes sense to use the filtered value because in this case at least it's guaranteed to produce a result in alignment with the data it operates on.

But I do see one use of an unfiltered index version of indexOf. There is a speed increase. If you filter out even numbers and you know the item is odd, but you want the original index, and the item is somewhere within the first half of the list. We can filter out the numbers we don't need to check, get to the odd number faster, and then get the index, returning the original index rather than the filtered index. But it might almost be faster to just get the index of the odd number anyways, I'd only see this as a speed increase if you work with millions of numbers. Filter is fast, but indexOf is faster.


Just noticed this edit (WHY do the forums not add edited posts to the unread list?).

Anyway, I thought that was kind of the point?  If the filtered data doesn't contain the item I ask for, I WANT it to return -1.  Otherwise, if it exists, I want the original index so I can directly index the original array.  I know I had a use case for this, but it's been so long now that I've forgotten what it was.

Also, I found a clever use of Link recently:
Code: (javascript) [Select]
// mini.Console.unregister()
// Unregisters a previously-registered entity.
// Arguments:
//     name: The name of the entity as passed to mini.Console.register().
mini.Console.unregister = function(name)
{
this.commands = mini.Link(this.commands)
.where(function(command) { return command.entity != name; })
.toArray();
};


It can be used to conditionally remove stuff from an array! ;D
  • Last Edit: May 08, 2015, 09:43:52 am by Lord English
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub