Skip to content
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

Feature request: _.push #2288

Closed
bholben opened this issue Apr 30, 2016 · 8 comments
Closed

Feature request: _.push #2288

bholben opened this issue Apr 30, 2016 · 8 comments

Comments

@bholben
Copy link

bholben commented Apr 30, 2016

When transforming data structures and adding to nested arrays (or creating an array on the fly), we frequently see the following pattern:

if (_.has(o, 'arr')) {
  o.arr.push(val);
} else {
  _.set(o, 'arr', [val]);
}

It would be convenient to replace this with a nice, readable single line. A lodash push method could follow the same signature as _.has, _.get, _.set, and friends:

_.push(o, 'arr', val);

For example, when looping through a data set...

if (_.has(myCalendar.eventsLookup, [userid, dateKey, 'calendarEntries'])) {
  _.get(myCalendar.eventsLookup, [userid, dateKey, 'calendarEntries']).push(calendarEntry);
} else {
  _.set(myCalendar.eventsLookup, [userid, dateKey, 'calendarEntries'], [calendarEntry]);
}

could be simplified to a single line...

_.push(myCalendar.eventsLookup, [userid, dateKey, 'calendarEntries'], calendarEntry);
@jdalton
Copy link
Member

jdalton commented Apr 30, 2016

I use this pattern in Lodash too though I'm not digging the name push as that seems too Array#push without the object property angle. I think there's something here but think it needs a bit more baking.

Internally I have a castSlice method that performs a slice if it's needed else returns the array without slicing. This method may fit as a cast method.

We'll keep an eye on the popularity of the request.

@jdalton jdalton closed this as completed Apr 30, 2016
@bholben
Copy link
Author

bholben commented Apr 30, 2016

Yeah, the name may be debatable, but I think the pattern is worthy.

I do like having push in the name as Array#push is the heart of the operation. Casting to an array feels more like a backup plan if the array does not exist. And in this case, I think it's a set that I'm seeking.

Perhaps _.pushSet() might make it more clear that it behaves like Lodash has/set/get (at least that's the signature I have in my head at the moment).

@bholben
Copy link
Author

bholben commented May 14, 2016

set to me says I'm writing to a plain object, but the underbelly of this is an array operation. The two scenarios I've outlined thus far are either pushing to the back end of the array or unshifting to the front. Maybe something like ensurePush or safePush or pushSafe.

This leaves us some flexibility to expand to other array operations later, whereas I think having set in the name feels limiting in the future.

@jdalton
Copy link
Member

jdalton commented May 14, 2016

Maybe something like ensurePush or safePush or pushSafe.

👍

@mk-pmb
Copy link

mk-pmb commented Aug 7, 2016

Here's my first draft of getOrAddKey. Feel free to join me in testing. I'll try and release the lib-demo-util 0.1.8 asap, until then you'll have to stub it somehow or use own tests.

@thorn0
Copy link
Contributor

thorn0 commented Oct 17, 2016

_.set(o, 'arr[]', val);

Why not make _.set understand such syntax?

It'd be a breaking change though. In the current version this line assigns val to o.arr[""].

@jdalton
Copy link
Member

jdalton commented Oct 17, 2016

@thorn0 See #1315.

@CongAn
Copy link

CongAn commented Jan 18, 2022

pushSafe.ts

import { get, set, isArray } from 'lodash'
import { PropertyPath } from 'lodash'

/**
 * 根据object对象的path路径,
 * 安全向数组(不存则会创建该数组)的末尾添加一个或多个元素,并返回新的长度。
 * @author https://github.com/CongAn
 */
export function pushSafe<V>(object: object, path: PropertyPath, ...items: V[]): number
export function pushSafe<V, T extends object>(object: T,  path: PropertyPath, ...items: V[]): number {
    let array = get(object, path)
    if (array === undefined) {
        set(object, path, array = [])
    }
    if (!isArray(array)) {
        throw new Error('The object path of push is not an array.');
    }
    return array.push(...items)
}

export default pushSafe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

5 participants