npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

onefish-twofish

v1.4.1

Published

A group of functions for common operations to perform on data comprised of arrays of objects. Can be used for data analysis, data visualization prep, etc.

Downloads

8

Readme

One Fish Two Fish

A group of functions for common operations to perform on data comprised of arrays of objects. Can be used for data analysis, data visualization prep, etc.

Usage

npm install onefish-twofish

Simple Functions:

  • cloneThing : Make a deep copy of an object.
  • expandNested : Expand an array of objects by a nested array's values.
  • flattenObject : Recursively flatten nested objects.
  • getUniqueVals : Return all unique values for a given field.
  • roundToDecimal : Rounds a value to the specified decimal place.
  • splitOut : Split out fields within a nested array to their own field.

Filtering:

Aggregate Functions:


cloneThing

cloneThing(thing) : Returns a deep clone of an object.

Takes 1 argument:

  • thing: The thing to clone

Ex:

let thing = {key:{obj:"value"}}
let clonedThing = cloneThing(thing)

thing.key.obj= "new value"

Result: Here we see the cloned object is unaffected by mutating the original object.

    thing: {key:{obj:"new value"}}
    clonedThing: {key:{obj:"value}}

expandNested

expandNested(arr, field,newField):

Expands an array of objects by values within a nested Array.

Takes 3 arguments

  • arr: The Original Array of objects.
  • field: The Name of the field containing the Array
  • newField: Optional- The name of the new field the values should be expanded to.

If blank, values will overwrite the original field.

Ex:

const arr = [
{val:1,val2:2,val3:["red","blue"]}
]
const result1 = expandNested (arr,"val3","val4")

const result2 = expandNested (arr,"val3")

Results: Here we expand val three, returning a new line/object for each item in val3.

    result1: [
         {val:1,val2:2,val3:["red","blue"],val4:"red"},
         {val:1,val2:2,val3:["red","blue"],val4:"blue"}
    ]

    result2: [
         {val:1,val2:2,val3:"blue"},
         {val:1,val2:2,val3:"red"}
    ]

flattenObject

flattenObject(object) : Returns a new object with any nested objects flattened. Keys will be combined and separated by an underscore.

Takes 1 argument:

  • object: The object to be flattened

Ex:

let obj = {someKey:{someNestedKey:{oneFish:"twoFish",redFish:"bluefish"}}}

let flatObj = flattenObject(obj)

Result: Here we return the object flattened so we can perform more operations on the data.

result:
  flatObj: {
    "someKey_someNestedKey_oneFish": "twoFish",
    "someKey_someNestedKey_redFish": "bluefish"
}


getUniqueVals

getUniqueVals(arr, field) : Returns an array of all the unique values a field contains

Takes 2 arguments:

  • arr: The array of objects
  • field: The field name as a string.

Ex:

const data = [
                {column_1:"one fish"},
                {column_1:"one fish"},
                {column_1:"two fish"}
            ]

result = getUniqueVals(data,"column_1")

result: ["one fish","two fish"]

roundToDecimal

roundToDecimal(num, decimalPlace) : Rounds to the specified decimal place

Takes 2 arguments:

  • num The number
  • decimalPlace The decimal place to be rounded to

Ex:

const num = 3.3333333333
result = roundToDecimal(num, 1)  // 3.3
result2 = roundToDecimal(num, 2) // 3.33
result3 = roundToDecimal(num, 2) // 3.333

splitOut

splitOut(arr, filterArr, field, newField) : Returns a new array of objects that splits out selected nested values into a new field. Does not modify the original Array field. Takes 4 isArguments:

  • filterArr: An Array of values to be filtered out.
  • arr: The Original Array
  • field: The name of the field within the object.
  • newField: The name of the new field that those values will be split out to. If blank the field will be titled the name of the original field + _copy

EX:

 let data = [
{column_1:["one fish","two fish","red fish","blue fish"]},
{column_1:["one fish","blue fish"]}
]

const result1 = splitOut(data,["red fish","blue fish"],"column_1")

const result2 = splitOut(data,["red fish","blue fish"],"column_1",column_2)

Results: Here we split the values "red fish" and "blue fish" out to their own key/column.

result1: [
{column_1:["one fish","two fish"],column_1_copy:["red fish","blue fish"]},
{column_1:["one fish"],column_1_copy:["blue fish"]}
]

result2: [
{column_1:["one fish","two fish"],column_2:["red fish","blue fish"]},
{column_1:["one fish"],column_2:["blue fish"]}
]

filterData

filterData(arr, filterArr) : Filters the data utilizing a filter array. The filter array is an array of filter objects.

Takes 2 arguments:

  • arr: The array to be filtered.
  • filterArr: The array of filter objects.

[!NOTE] Filter objects usually consist of three keys/fields.

  • field: The field to apply the filter to as a string.
  • opertation: The operation to apply for filtering.
  • value: The value that should be applied.

Let's start out with the most basic example.

Ex:

let arr = {field: "oneFish"},
          {field: "twoFish"}
          {field: "oneFish"}

let filterObj =  { field: "field", operation: "===", value: "oneFish" },

let filteredArr = filterData(arr,[filterObj])

<!-- result:
  filteredArr: [
                {field: "oneFish"},
                {field: "oneFish"}
                ]
                 -->

[!NOTE] Filter objects are stored in an array because they can be chained together:

Ex:

let arr = {field: "oneFish",someOtherField: "redFish"},
          {field: "twoFish",someOtherField: "blueFish}
          {field: "oneFish",someOtherField: "blueFish}

let filterArr =  [
                    { field: "field", operation: "===", value: "oneFish" },
                    { field: "someOtherField", operation: "===", value: "redFish" },
                 ]

let filteredArr = filterData(arr,filterArr)

<!-- result:
  filteredArr: [
                {field: "oneFish",someOtherField: "redFish},
                ]
                 -->

[!NOTE] There are many operations that you can filter by:


Filter Objects:

| Operation | Usage | | ----------- | ------------------------------------------- | | "===" | strict equivalence | | "==" | shallow equivalence | | "!==" | strict inequivalence | | "!=" | shallow inequivalence | | ">=" | greater than or equal to | | ">" | greater than | | "<=" | less than or equal to | | "<" | less than | | "includes" | whether an array includes the value | | "!includes" | whether an array does not include the value | | "or" | See below for usage |


Filtering by numeric values

You can filter by numeric operations like greater than, less than etc.

Source Data

let arr = [{field: "oneFish",someValue:4,someArray:["blackFish","oldFish","newFish"]},
          {field: "twoFish",someValue:2,someArray:["blackFish","oldFish","newFish"]}
          {field: "oneFish",someValue:4,someArray:["blackFish","newFish"]}]

Function

let filterObj =  { field: "someValue", operation: ">", value: 3 }

let filteredArr = filterData(arr,[filterObj])

Result:

 [
    {field: "oneFish", someValue:4, someArray:["blackFish","oldFish","newFish"]},
    {field: "oneFish", someValue:4, someArray:["blackFish","newFish"]}
]

Filtering nested arrays

You can filter by objects included or not included in arrays.

Source Data:

let arr = [{field: "oneFish",someValue:4,someArray:["blackFish","oldFish","newFish"]},
          {field: "twoFish",someValue:2,someArray:["blackFish","oldFish","newFish"]}
          {field: "oneFish",someValue:4,someArray:["blackFish","newFish"]}]

Function:

let filterObj =  { field: "someArray", operation: "includes", value: "oldFish" }

let filteredArr = filterData(arr,[filterObj])

Result:

 [
    {field: "oneFish",someValue:4,someArray:["blackFish","oldFish","newFish"]},
    {field: "twoFish",someValue:2,someArray:["blackFish","oldFish","newFish"]}
]

Combining filters

Filters can be combined for complex filtering.

Source Data:

let arr = [{field: "oneFish",someValue:4,someArray:["blackFish","oldFish","newFish"]},
          {field: "twoFish",someValue:2,someArray:["blackFish","oldFish","newFish"]}
          {field: "oneFish",someValue:4,someArray:["blackFish","newFish"]}]

Function:

let filters =  [{ field: "someArray", operation: "includes", value: "oldFish" },
                { field: "someValue", operation: ">", value: 3 }
                ]
let filteredArr = filterData(arr,filterObj)

Result:

[
    {field: "oneFish",someValue:4,someArray:["blackFish","oldFish","newFish"]}
]


aggregateThings

aggregateThings(arr, groupArr, aggObjArr,isStrict) : Aggregates the data by a group of fields and returns specified operations.

Takes 4 arguments:

  • arr: The array to be aggregated.
  • groupArr: The array of fields to group by as strings.
  • aggObjArr: An array of aggregation objects.
  • isStrict: Optional Whether to perform strict equivalence.

[!NOTE] By default, strict is it set to false. Useful for things like, separating falsy values, if you wanted to keep empty strings("") and NULL values on separate lines. By default, empty strings and NULLs will be combined.

Aggregate Objects consist of two fields

  • field: The field to apply the aggregation to as a string.
  • opertation: The aggregation function to apply as a string. (You can pass custom functions to the operation if so desired)

Let's start out with a basic example.

Source Data:


let sourceData = [
{region: "NA",score:30},
{region: "NA",score:20},
{region: "EMEA", score: 10},
{region: "EMEA", score:20}
]

Function: Here we want to return the average of score across each region.


let aggObj = [{field:"score",operation:"average"}]

let aggregatedData = aggregateThings(sourceData,["region"],aggObj)

Result:


[
{region:NA, score:25,count:2},
{region:EMEA, score:15, count:2}
]

[!NOTE] Aggregation functions always include count. If all you need is the count, the aggObj array can be ommited. Ex: aggregateThings(arr,["field one","field two"])


Aggregation Operations

Aggregation objects can include the following aggregation operations: |Operation|Usage| |---------|-----| |"sum"|The sum of the specified field| |"average"|The mean of the specified field| |"min"|The minimum value within that field| |"max"|The minimum value within that field| |"%>="+num|Returns the percentage of the grouped field that is greater than or equal to a specified number. Ex: "%>=4" returns the percent greater than or equal to 4| |"%>"+num|Returns the percentage of the grouped field that is greater than a specified number.| |"%<="+num|Returns the percentage of the grouped field that is less than or equal to a specified number.| |"%<"+num|Returns the percentage of the grouped field that is greater than a specified number.|

Let's see a more compound example:

Source Data:


let dataArr = [
{ currentSubscribers: 8, newSubscribers: 5, region: "NA", company: "Max" },
{ currentSubscribers: 5, newSubscribers: 4, region: "NA", company: "Netflix" },
{ currentSubscribers: 20, newSubscribers: 5, region: "NA", company: "Amazon" },
{ currentSubscribers: 17, newSubscribers: 1, region: "APAC", company: "Max" },
{ currentSubscribers: 15, newSubscribers: 6, region: "APAC", company: "Netflix" },
{ currentSubscribers: 6, newSubscribers: 2, region: "APAC", company: "Amazon" },
{ currentSubscribers: 9, newSubscribers: 2, region: "EMEA", company: "Max" },
{ currentSubscribers: 8, newSubscribers: 4, region: "EMEA", company: "Netflix" },
{ currentSubscribers: 8, newSubscribers: 4, region: "EMEA", company: "Amazon" },
];

Function: Here we return a number of aggregations accross each company:


let test1 = aggregateThings(dataArr, ["company"], [
{ field: "currentSubscribers", operation: "min" },
{ field: "currentSubscribers", operation: "average" },
{ field: "newSubscribers", operation: "max" },
{ field: "newSubscribers", operation: "%>3" },
{ field: "newSubscribers", operation: "sum" },
]);

Result:


[
{
"company": "Max",
"min_of_currentSubscribers": 8,
"average_of_currentSubscribers": 11.333333333333334,
"max_of_newSubscribers": 5,
"%_newSubscribers_greater_than_3": 33.33333333333333,
"sum_of_newSubscribers": 8,
"count": 3
},
{
"company": "Netflix",
"min_of_currentSubscribers": 5,
"average_of_currentSubscribers": 9.333333333333334,
"max_of_newSubscribers": 6,
"%_newSubscribers_greater_than_3": 100,
"sum_of_newSubscribers": 14,
"count": 3
},
{
"company": "Amazon",
"min_of_currentSubscribers": 6,
"average_of_currentSubscribers": 11.333333333333334,
"max_of_newSubscribers": 5,
"%_newSubscribers_greater_than_3": 66.66666666666666,
"sum_of_newSubscribers": 11,
"count": 3
}
]

Passing in Custom Functions

You can pass your own functions into the aggregation object. When the aggregator runs, it will pass two arguments to your function:

  • arr The array of aggregated items for the function to be performed on.
  • aggObject The aggregation object itself.

[!IMPORTANT] Your function must return an object with the key value pair you are adding. Take the below example.

Source Data:


let dataArr = [
{ currentSubscribers: 8, newSubscribers: 5, topGenres: ["comedy", "action", "drama"], region: "NA", company: "Max" },
{ currentSubscribers: 5, newSubscribers: 4, topGenres: ["drama"], region: "NA", company: "Netflix" },
{ currentSubscribers: 20, newSubscribers: 5, topGenres: ["comedy"], region: "NA", company: "Amazon" },
{ currentSubscribers: 17, newSubscribers: 1, topGenres: ["action"], region: "APAC", company: "Max" },
{ currentSubscribers: 15, newSubscribers: 6, topGenres: ["drama"], region: "APAC", company: "Netflix" },
{ currentSubscribers: 6, newSubscribers: 2, topGenres: ["comedy", "action", "drama"], region: "APAC", company: "Amazon" },
{ currentSubscribers: 9, newSubscribers: 2, topGenres: ["comedy"], region: "EMEA", company: "Max" },
{ currentSubscribers: 8, newSubscribers: 4, topGenres: ["action"], region: "EMEA", company: "Netflix" },
{ currentSubscribers: 8, newSubscribers: 4, topGenres: ["drama"], region: "EMEA", company: "Amazon" },
];

Custom Function: Here we write a function ro return a count of values where top genre includes comedy.


function countComedy(arr, aggObj) {
const countOfComedy = arr.filter((item) => item[aggObj.field].includes("comedy")).length;
const val = { "#\_Top_Genre_Comedy": countOfComedy };
return val;
}

Function


let test1 = aggregateThings(dataArr, ["company"], [{ field: "topGenres", operation: countComedy }]);

Result


[
{
"company": "Max",
"#_Top_Genre_Comedy": 2,
"count": 3
},
{
"company": "Netflix",
"#_Top_Genre_Comedy": 0,
"count": 3
},
{
"company": "Amazon",
"#_Top_Genre_Comedy": 2,
"count": 3
}
]