-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Selecting elements between two items? #14
Comments
Hey @tonygermano, sorry for the super slow reply. I'm not exactly maintaining this project, and also I think I had notifications turned off. 😬 I still use Qim myself though, so that shouldn't necessarily stop you from using it. 😄 Anywho, to answer your question... I wouldn't recommend making stateful navigators like that (i.e. creating the state inside the factory function), because navigators should be reusable. In other words, you should be able to do this: const $betweenThisAndThat = $between(this, that); And then use The right way to do this unfortunately isn't going to be very terse. I think you really want to mimic the const newObj = update([$between(e => e[0] == 'b', e => e[0] == 'b' && e[1] == 2), $each, $none], myObj); To implement that, you have to create a "core navigator". Hold onto your butts... function $between(state1Fn, state2Fn) {
return $traverse({
select: (object, next) => {
let state = 0;
function isBetween(item) {
if (state === 0 && state1Fn(item)) state = 1
else if (state === 1 && state2Fn(item)) state = 2
return state === 1;
}
// Pass the between items to the rest of the query.
return next(select([
$each,
isBetween
], object));
},
update: (object, next) => {
let state = 0;
const betweenKeys = [];
// Save off the keys of the between items.
function isBetweenPair([key, item]) {
if (state === 0 && state1Fn(item)) state = 1
else if (state === 1 && state2Fn(item)) state = 2
if (state === 1) {
betweenKeys.push(key);
}
return state === 1;
}
// Pass the between items to the rest of the query.
const result = next(select([
$eachPair,
isBetweenPair,
$apply((key, value) => value)
], object));
// Now replace the between items.
return update([
$eachPair,
$apply(([key, value]) => {
if (betweenKeys.includes(key)) {
if (key in result) {
return [key, result[key]];
}
return $none;
}
return [key, value];
})
], object);
return result;
}
})
} Note how the state is local to the particular select or update. I don't promise this is fully debugged or anything, but I tried to make it relatively general purpose while not making it too hard to grok. The select is fairly straightforward. It looks very similar to what you were doing. The update is more complicated, because you have to update the subset and then merge it back into the object (which could be an array or an object). There are some edge cases that would need to be covered by error messages if this were part of the library. Stateful predicates are an interesting idea though! |
I just started playing with your library, and I really like it. Thank you for sharing! I had a question where I wasn't sure of the best way to do something. I did end up figuring out a solution, but I don't know if there's a better way.
I have an array where I wanted to remove objects starting (inclusive) with the element that meets one condition and ending (exclusive) with the element that meets a second condition.
For example, remove elements starting with the first occurrence of type
b
until['b',2]
is encountered.I ended up writing this method...
and then using it like this...
It does what I want, but the stateful predicate seems out of place.
The text was updated successfully, but these errors were encountered: