Repository: char0n/ramda-adjunct
Pull request #2384 (2022-10-19 13:17:41)

Feature: Add `sortByProp`
Implemented `sortByProp` function.

Issue: #1241 

nolleto: Hey @char0n , can you review my PR? 🫣🥺
char0n: @nolleto working on it now. Thanks for contributing!

Patch:
diff --git a/src/index.js b/src/index.js
index 0931ef0b1a..4bcb40b1fc 100644
--- a/src/index.js
+++ b/src/index.js
@@ -161,6 +161,7 @@ export { default as toArray } from './toArray';
 export { default as allUnique } from './allUnique';
 export { default as notAllUnique } from './notAllUnique';
 export { default as sortByProps } from './sortByProps';
+export { default as sortByProp } from './sortByProp';
 export { default as sortByPaths } from './sortByPaths';
 export { default as skipTake } from './skipTake';
 export { default as rangeStep } from './rangeStep';
diff --git a/src/sortByProp.js b/src/sortByProp.js
new file mode 100644
index 0000000000..464257d9a3
--- /dev/null
+++ b/src/sortByProp.js
@@ -0,0 +1,45 @@
+import { __, append, identity, useWith } from 'ramda';
+
+import sortByProps from './sortByProps';
+
+/**
+ * Sort a list of objects by a property.
+ *
+ * @func sortByProp
+ * @memberOf RA
+ * @since {@link https://char0n.github.io/ramda-adjunct/3.4.0|v3.4.0}
+ * @category List
+ * @sig k -> [{k: v}] -> [{k: v}]
+ * @param {Array.<string>} prop The property in the list param to sort by
+ * @param {Array.<object>} list A list of objects to be sorted
+ * @return {Array.<object>} A new list sorted by the property in the prop param
+ * @example
+ *
+ * // sorting list of tuples
+ * const sortByFirstItem = sortByProp(0);
+ * const listOfTuples = [[-1, 1], [-2, 2], [-3, 3]];
+ * sortByFirstItem(listOfTuples); // => [[-3, 3], [-2, 2], [-1, 1]]
+ *
+ * // sorting list of objects
+ * const sortByName = sortByProp('name');
+ * const alice = {
+ *   name: 'ALICE',
+ *   age: 101,
+ * };
+ * const bob = {
+ *   name: 'Bob',
+ *   age: -10,
+ * };
+ * const clara = {
+ *   name: 'clara',
+ *   age: 314.159,
+ * };
+ * const people = [clara, bob, alice];
+ * sortByName(people); // => [alice, bob, clara]
+ */
+
+const addValueInAnArray = append(__, []);
+
+const sortByProp = useWith(sortByProps, [addValueInAnArray, identity]);
+
+export default sortByProp;
diff --git a/src/sortByProps.js b/src/sortByProps.js
index 51e40c0dc3..e5876bb4fe 100644
--- a/src/sortByProps.js
+++ b/src/sortByProps.js
@@ -1,4 +1,4 @@
-import { reduce, either, curry, prop, sort, comparator, map, lt } from 'ramda';
+import { comparator, curry, either, lt, map, prop, reduce, sort } from 'ramda';
 
 /**
  * Sort a list of objects by a list of props (if first prop value is equivalent, sort by second, etc).
diff --git a/types/index.d.ts b/types/index.d.ts
index a6a9afde98..1b7cac37e9 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1703,6 +1703,14 @@ export function padCharsStart(
 export function padStart(targetLength: number, value: string): string;
 export function padStart(targetLength: number): (value: string) => string;
 
+/**
+ * Sort a list of objects by a property.
+ */
+export function sortByProp<T>(prop: string | number, list: readonly T[]): T[];
+export function sortByProp(
+  prop: string | number
+): <T>(list: readonly T[]) => T[];
+
 /**
  * Sort a list of objects by a list of props (if first prop value is equivalent, sort by second, etc).
  */


Test patch:
diff --git a/test/sortByProp.js b/test/sortByProp.js
new file mode 100644
index 0000000000..087dd1312f
--- /dev/null
+++ b/test/sortByProp.js
@@ -0,0 +1,70 @@
+import { assert } from 'chai';
+
+import * as RA from '../src';
+
+describe('sortByProp', function () {
+  const alice = {
+    name: 'ALICE',
+    age: 101,
+    lastName: 'Smith',
+  };
+  const bob = {
+    name: 'Bob',
+    age: -10,
+    lastName: 'Smith',
+  };
+  const clara = {
+    name: 'clara',
+    age: 314.159,
+    lastName: 'Kris',
+  };
+  const people = [clara, bob, alice];
+
+  context('given list of objects', function () {
+    specify('should sort by existing property', function () {
+      assert.deepEqual(RA.sortByProp('name', people), [alice, bob, clara]);
+    });
+
+    context('given property to sort by does not exist', function () {
+      specify('should return original list', function () {
+        assert.deepEqual(RA.sortByProp('p', people), people);
+      });
+    });
+  });
+
+  context('given list of strings', function () {
+    specify('should return unmodified list of strings', function () {
+      assert.deepEqual(RA.sortByProp('name', ['a', 'b', 'c']), ['a', 'b', 'c']);
+    });
+  });
+
+  context('given list of tuples', function () {
+    specify('should sort by tuple value', function () {
+      assert.deepEqual(
+        RA.sortByProp(0, [
+          [-1, 1],
+          [-2, 2],
+          [-3, 3],
+        ]),
+        [
+          [-3, 3],
+          [-2, 2],
+          [-1, 1],
+        ]
+      );
+    });
+  });
+
+  context('given empty list', function () {
+    specify('should return empty list', function () {
+      assert.deepEqual(RA.sortByProp('name', []), []);
+    });
+  });
+
+  it('should be curried', function () {
+    assert.deepEqual(
+      RA.sortByProp('name')(people),
+      RA.sortByProp('name', people)
+    );
+  });
+});
diff --git a/types/test/sortByProp.ts b/types/test/sortByProp.ts
new file mode 100644
index 0000000000..95eb18f647
--- /dev/null
+++ b/types/test/sortByProp.ts
@@ -0,0 +1,29 @@
+import * as RA from 'ramda-adjunct';
+
+const alice = {
+  name: 'ALICE',
+  age: 101,
+  lastName: 'Smith',
+};
+const bob = {
+  name: 'Bob',
+  age: -10,
+  lastName: 'Smith',
+};
+const clara = {
+  name: 'clara',
+  age: 314.159,
+  lastName: 'Kris',
+};
+const people = [clara, bob, alice];
+
+RA.sortByProp('name')(people); // $ExpectType { name: string; age: number; lastName: string; }[]
+RA.sortByProp('p')(people); // $ExpectType { name: string; age: number; lastName: string; }[]
+// $ExpectType number[][]
+RA.sortByProp(0)([
+  [1, 2],
+  [3, 4],
+]);
+
+// @ts-expect-error
+RA.sortByProp('name')(123);