New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@santi100/bisect-lib

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@santi100/bisect-lib - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

.github/labeler.yml

7

cjs/index.d.ts
type Comparator<T = unknown> = (a: T, b: T) => number;
type Order = 'ascending' | 'descending';
/**

@@ -11,4 +12,4 @@ * @since 0.0.3

/**
* Inclusive optional ending index. Defaults to the length of the array..
*/
* Inclusive optional ending index. Defaults to the length of the array.
*/
end?: number;

@@ -22,3 +23,3 @@ /**

*/
order?: 'ascending' | 'descending';
order?: Order;
/**

@@ -25,0 +26,0 @@ * Optional custom comparator. Is compatible with {@link Array.prototype.sort}.

"use strict";
exports.__esModule = true;
exports.bisectMultiple = exports.bisect = void 0;
var cjs_1 = require("@santi100/equal-lib/cjs");
var equal_lib_1 = require("@santi100/equal-lib");
var _a = Number.EPSILON, EPSILON = _a === void 0 ? 1.0000000000000002 - 1 : _a;
function DEFAULT_ASCENDING_COMPARATOR(a, b) {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
function DEFAULT_DESCENDING_COMPARATOR(a, b) {
if (a < b)
return 1;
if (a > b)
return -1;
return 0;
}
/**

@@ -18,13 +33,16 @@ * Searches for `target` through `array` with an iterative binary-search algorithm (designed for sorted arrays).

function bisect(array, target, opts) {
if (opts === void 0) { opts = {}; }
if (!Array.isArray(array)) {
throw new TypeError("\"array\" must be an Array. Received \"".concat(String(array), "\"."));
}
var _a = opts || {}, comparator = _a.comparator, // Satisfies idea #1, see `ideas.md`
_b = _a.order, // Satisfies idea #1, see `ideas.md`
order = _b === void 0 ? 'ascending' : _b, // Satisfies idea #3, see `ideas.md`
_c = _a.epsilon, // Satisfies idea #3, see `ideas.md`
epsilon = _c === void 0 ? Number.EPSILON || 0 : _c, // Satisfies idea #5, see `ideas.md`
_d = _a.start, // Satisfies idea #5, see `ideas.md`
var _a = opts.order, order = _a === void 0 ? 'ascending' : _a, // Satisfies idea #3, see `ideas.md`
_b = opts.comparator, // Satisfies idea #3, see `ideas.md`
comparator = _b === void 0 ? order === 'ascending'
? DEFAULT_ASCENDING_COMPARATOR
: DEFAULT_DESCENDING_COMPARATOR : _b, // Satisfies idea #1, see `ideas.md`
_c = opts.epsilon, // Satisfies idea #1, see `ideas.md`
epsilon = _c === void 0 ? EPSILON : _c, // Satisfies idea #5, see `ideas.md`
_d = opts.start, // Satisfies idea #5, see `ideas.md`
start = _d === void 0 ? 0 : _d, // Satisfies idea #4, see `ideas.md`
_e = _a.end // Satisfies idea #4, see `ideas.md`
_e = opts.end // Satisfies idea #4, see `ideas.md`
, // Satisfies idea #4, see `ideas.md`

@@ -41,3 +59,3 @@ end = _e === void 0 ? array.length : _e // Satisfies idea #4, see `ideas.md`

}
else if ((0, cjs_1.deepEquality)(array[middle], target)) {
else if ((0, equal_lib_1.deepEquality)(array[middle], target)) {
return middle;

@@ -47,3 +65,6 @@ }

var cmp = comparator(target, array[middle]);
if ((order === 'ascending' && cmp < 0) || (order === 'descending' && cmp > 0)) {
if (typeof cmp !== 'number')
throw new TypeError("Comparator function is invalid. Got value \"".concat(cmp, "\" of type \"").concat(typeof cmp, "\"."));
if ((order === 'ascending' && cmp < 0) ||
(order === 'descending' && cmp > 0)) {
right = middle - 1;

@@ -80,3 +101,3 @@ }

var i = firstIndex + 1;
while ((0, cjs_1.deepEquality)(array[i], target) && i < array.length) {
while ((0, equal_lib_1.deepEquality)(array[i], target) && i < array.length) {
indices.push(i);

@@ -83,0 +104,0 @@ i++;

@@ -43,3 +43,3 @@ # Code of Conduct

that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
permanently any contributor for other behaviors that I deem inappropriate,
threatening, offensive, or harmful.

@@ -59,5 +59,65 @@

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting me at <santyrojasprieto9+githubissues@gmail.com>.
All complaints will be reviewed and investigated and will result in a response that
reported by contacting me at <santyrojasprieto9+githubissues@gmail.com>. All complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. I will maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Further details of specific enforcement policies may be posted separately.
## Enforcement Guidelines
I will follow these Community Impact Guidelines in determining
the consequences for any action I deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from me, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
<https://www.contributor-covenant.org/faq>. Translations are available
at <https://www.contributor-covenant.org/translations>.
[homepage]: https://www.contributor-covenant.org
[Mozilla CoC]: https://github.com/mozilla/diversity

@@ -11,2 +11,7 @@ Here are some ideas for additional features that could be added to the bisect function:

5. ~~Error tolerance: For arrays that contain floating-point numbers, it may be useful to allow for some degree of error tolerance in the comparison of elements. This would help avoid situations where the target is not found due to rounding errors.~~
5. ~~Error tolerance: For arrays that contain floating-point numbers, it may be useful to allow for some degree of error tolerance in the comparison of elements. This would help avoid situations where the target is not found due to rounding errors.~~
6. Currently, the comparator option only works for certain types of data (namely, numbers and objects that can be compared with `deepEquality`). It might be useful to add support for other types of data, such as strings or dates. This could be done by adding more type constraints to the `Comparator` type.
7. You might consider adding some validation for the input values of the comparator function. For example, you could throw an error if the comparator doesn't return a valid number.
8. You could add a feature to allow the `bisect` function to work with non-ascending order, in addition to the existing `ascending` and `descending` options.
9. Another possible feature would be to add an option for the `bisect` function to return all occurrences of the target element in the array, instead of just the first occurrence. This could be useful in cases where the array contains duplicates of the target element.
10. The current implementation uses the `deepEquality` function to compare objects for equality. Depending on the use case, it might be more appropriate to use a different comparison function, such as one that only compares certain fields of the objects.
type Comparator<T = unknown> = (a: T, b: T) => number;
type Order = 'ascending' | 'descending';
/**

@@ -11,4 +12,4 @@ * @since 0.0.3

/**
* Inclusive optional ending index. Defaults to the length of the array..
*/
* Inclusive optional ending index. Defaults to the length of the array.
*/
end?: number;

@@ -22,3 +23,3 @@ /**

*/
order?: 'ascending' | 'descending';
order?: Order;
/**

@@ -25,0 +26,0 @@ * Optional custom comparator. Is compatible with {@link Array.prototype.sort}.

@@ -9,3 +9,4 @@ {

],
"version": "0.0.4",
"description": "Santi's Bisect Library: Binary search in a lightweight package.",
"version": "0.0.5",
"main": "index.js",

@@ -16,3 +17,3 @@ "author": "santi100a <santyrojasprieto9@gmail.com>",

"@types/jest": "^29.4.0",
"jest": "^29.4.3",
"jest": "^29.5.0",
"typescript": "^4.9.5"

@@ -29,4 +30,4 @@ },

"dependencies": {
"@santi100/equal-lib": "^1.0.4"
"@santi100/equal-lib": "^1.0.8"
}
}

@@ -6,9 +6,23 @@ # Santi's Bisect Library

[![License](https://img.shields.io/github/license/santi100a/bisect-lib.svg)](https://github.com/santi100a/bisect-lib)
[![npm bundle size](https://img.shields.io/bundlephobia/min/@santi100/bisect-lib)](https://bundlephobia.com/package/@santi100/bisect-lib@latest)
- 🚀 Lightweight and fast
- 👴 ES3-compliant*
- 🚀 Lightweight and fast[^](#disclaimers)
- 👴 ES3-compliant[*](#disclaimers)
- 💻 Portable between the browser and Node.js
**Hasn't been tested in an actual ES3 environment. Feel free to open an issue or pull request if you find any non-ES3 thing.*
## What's this?
This is a lightweight, fast library for doing [*binary search*](#what-is-binary-search).
### What is "binary search"?
Binary search is a search algorithm that finds the position of a target value within a sorted array or list. It works by repeatedly dividing the search interval in half. At each step, the algorithm compares the target value with the middle element of the array or list. If the target value matches the middle element, its position is returned. If the target value is less than the middle element, the search is narrowed to the lower half of the array. If the target value is greater than the middle element, the search is narrowed to the upper half of the array. This process is repeated until the target value is found or the search interval is empty. Binary search has a time complexity of $O(\log{n})$, making it much faster than linear search for large arrays or lists.
### What is "deep equality"?
"Deep equality" refers to the concept of comparing two values for equality not just on a shallow level, but on a deep level as well. When checking for deep equality, not only are the top-level values of the two objects being compared checked, but also their nested values. This can be particularly useful when comparing complex data structures like objects or arrays. For example, if two objects have the same keys but their values are objects themselves, checking for shallow equality would only compare the reference to those objects, not their internal properties. Checking for deep equality would compare those properties as well. JavaScript compares objects with [*referential equality*](#what-is-referential-equality) by default.
### What is "referential equality"?
"Referential equality" is a type of equality that compares if two variables refer to the exact same object in memory. In other words, it checks if the two variables point to the same memory address. This is often used when checking if two variables are the same instance of an object. If two variables have referential equality, any change made to one of them will also affect the other. In JavaScript, referential equality can be checked using the `===` operator.
## Contribute
Wanna contribute? [File an issue](https://github.com/santi100a/bisect-lib/issues) or [pull request](https://github.com/santi100a/bisect-lib/pulls)!
Make sure you follow the [contribution Code of Conduct](https://github.com/santi100a/bisect-lib/blob/main/CODE_OF_CONDUCT.md).
## Installation

@@ -20,3 +34,3 @@ - Via NPM: `npm install @santi100/bisect-lib`

## API
All functions support deep equality.
All functions support [*deep equality*](#what-is-deep-equality).
- `function bisect<T = unknown>(array: T[], target: T): number;` Searches for `target` through `array` with a recursive binary-search algorithm (designed for sorted arrays). Returns the index of the first ocurrence of `target`, or -1 if it's not present.

@@ -28,5 +42,10 @@

```
Keep in mind this is **NOT** a bug in my code, it's just how binary search algorithms work.
- `function bisectMultiple<T extends C, C = T>(array: T[], target: T, opts?: BisectOptions<C>): number;`
Searches for `target` through `array` with an iterative binary-search algorithm
(designed for sorted arrays) and returns an array of indices. See `bisect` for details.}
(designed for sorted arrays) and returns an array of indices. See `bisect` for details.
### Disclaimers
**Hasn't been tested in an actual ES3 environment. Feel free to open an issue or pull request if you find any non-ES3 thing.*
*^The source code is about 3 kilobytes.*

@@ -1,5 +0,7 @@

import { deepEquality } from '@santi100/equal-lib/cjs';
import { deepEquality } from '@santi100/equal-lib';
const { EPSILON = 1.0000000000000002 - 1 } = Number;
type Comparator<T = unknown> = (a: T, b: T) => number;
type Order = 'ascending' | 'descending';
/**

@@ -9,26 +11,35 @@ * @since 0.0.3

interface BisectOptions<C = unknown> {
/**
* Inclusive optional starting index. Defaults to 0.
*/
start?: number;
/**
* Inclusive optional ending index. Defaults to the length of the array..
*/
end?: number;
/**
* Optional epsilon for floating-point comparisons. Defaults to `Number.EPSILON`.
*/
epsilon?: number;
/**
* Optional order. Defaults to 'ascending'.
*/
order?: 'ascending' | 'descending';
/**
* Optional custom comparator. Is compatible with {@link Array.prototype.sort}.
*/
comparator?: Comparator<C>;
}
/**
* Inclusive optional starting index. Defaults to 0.
*/
start?: number;
/**
* Inclusive optional ending index. Defaults to the length of the array.
*/
end?: number;
/**
* Optional epsilon for floating-point comparisons. Defaults to `Number.EPSILON`.
*/
epsilon?: number;
/**
* Optional order. Defaults to 'ascending'.
*/
order?: Order;
/**
* Optional custom comparator. Is compatible with {@link Array.prototype.sort}.
*/
comparator?: Comparator<C>;
}
function DEFAULT_ASCENDING_COMPARATOR(a: any, b: any) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
function DEFAULT_DESCENDING_COMPARATOR(a: any, b: any) {
if (a < b) return 1;
if (a > b) return -1;
return 0;
}
/**
* Searches for `target` through `array` with an iterative binary-search algorithm (designed for sorted arrays).
* Searches for `target` through `array` with an iterative binary-search algorithm (designed for sorted arrays).
* **Tests show it doesn't work correctly for unsorted arrays, so you shouldn't pass them to this function:

@@ -39,49 +50,61 @@ * ```javascript

* It's not a bug, it's just how binary search algorithms work.
* @param array The array to look through.
* @param array The array to look through.
* @param target The item to look for.
* @param opts Optional object of options. See {@link BisectOptions}.
* @param opts Optional object of options. See {@link BisectOptions}.
* @returns The index of the first ocurrence of `target`, or -1 if it's not present.
*/
*/
function bisect<T extends C, C = T>(
array: T[],
target: T,
opts?: BisectOptions<C>
array: T[],
target: T,
opts: BisectOptions<C> = {}
): number {
if (!Array.isArray(array)) {
throw new TypeError(`"array" must be an Array. Received "${String(array)}".`);
}
if (!Array.isArray(array)) {
throw new TypeError(
`"array" must be an Array. Received "${String(array)}".`
);
}
const {
comparator, // Satisfies idea #1, see `ideas.md`
order = 'ascending', // Satisfies idea #3, see `ideas.md`
epsilon = Number.EPSILON || 0, // Satisfies idea #5, see `ideas.md`
start = 0, // Satisfies idea #4, see `ideas.md`
end = array.length // Satisfies idea #4, see `ideas.md`
} = opts || {};
let left = start;
let right = end - 1;
const {
order = 'ascending', // Satisfies idea #3, see `ideas.md`
comparator = order === 'ascending'
? DEFAULT_ASCENDING_COMPARATOR
: DEFAULT_DESCENDING_COMPARATOR, // Satisfies idea #1, see `ideas.md`
epsilon = EPSILON, // Satisfies idea #5, see `ideas.md`
start = 0, // Satisfies idea #4, see `ideas.md`
end = array.length // Satisfies idea #4, see `ideas.md`
} = opts;
let left = start;
let right = end - 1;
while (left <= right) {
const middle = Math.floor((left + right) / 2);
if (
typeof array[middle] === 'number' &&
Math.abs(array[middle] as number - (target as number)) <= epsilon) {
return middle;
} else if (deepEquality(array[middle], target)) {
return middle;
} else if (comparator) {
const cmp = comparator(target, array[middle]);
if ((order === 'ascending' && cmp < 0) || (order === 'descending' && cmp > 0)) {
right = middle - 1;
} else {
left = middle + 1;
}
} else if (array[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
while (left <= right) {
const middle = Math.floor((left + right) / 2);
if (
typeof array[middle] === 'number' &&
Math.abs((array[middle] as number) - (target as number)) <= epsilon
) {
return middle;
} else if (deepEquality(array[middle], target)) {
return middle;
} else if (comparator) {
const cmp = comparator(target, array[middle]);
if (typeof cmp !== 'number')
throw new TypeError(
`Comparator function is invalid. Got value "${cmp}" of type "${typeof cmp}".`
);
if (
(order === 'ascending' && cmp < 0) ||
(order === 'descending' && cmp > 0)
) {
right = middle - 1;
} else {
left = middle + 1;
}
} else if (array[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return -1;
return -1;
}

@@ -99,16 +122,18 @@

*/
function bisectMultiple<T extends C, C = unknown>(
array: T[], target: T, opts: BisectOptions<C> = {}
function bisectMultiple<T extends C, C = unknown>(
array: T[],
target: T,
opts: BisectOptions<C> = {}
): number[] {
const firstIndex = bisect(array, target, opts);
const indices: number[] = firstIndex === -1 ? [] : [firstIndex];
let i = firstIndex + 1;
while (deepEquality(array[i], target) && i < array.length) {
indices.push(i);
i++;
}
return indices;
const firstIndex = bisect(array, target, opts);
const indices: number[] = firstIndex === -1 ? [] : [firstIndex];
let i = firstIndex + 1;
while (deepEquality(array[i], target) && i < array.length) {
indices.push(i);
i++;
}
return indices;
}
export default bisect;
export { bisect, bisectMultiple };
export { bisect, bisectMultiple };

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc