假设我已经有这些文章的数组,按最低价格到最高价格排序:
[
{ title: "Article 3", price: 1.49 },
{ title: "Article 1", price: 3.00 },
{ title: "Article 4", price: 5.99 },
{ title: "Article 2", price: 19.99 }
]
基本上我想将另一篇文章推送到数组中的正确位置(按价格)。我怎么能这样做?
我推送的新文章可能具有以下属性:
{ title: "Article 5", price: 12.00 }
我希望文章出现在索引3(第4条和第2条之间)。
我使用@ klutt的二元搜索算法答案创建了一个原型方法:
Array.prototype.pushSorted = function(el, compareFn) {
this.splice((function(arr) {
var m = 0;
var n = arr.length - 1;
while(m <= n) {
var k = (n + m) >> 1;
var cmp = compareFn(el, arr[k]);
if(cmp > 0) m = k + 1;
else if(cmp < 0) n = k - 1;
else return k;
}
return -m - 1;
})(this), 0, el);
return this.length;
};
const sortByPrice = (a, b) => a.price > b.price;
theArray.pushSorted({ title: "Article 5", price: 12.00 }, sortByPrice);
答案 0 :(得分:2)
为了避免每次都对数组进行排序,您可以遍历数组,直到找到价格较高的元素,然后使用array.splice(index, 0, element)
将元素插入正确的位置:
var array = [
{ title: "Article 3", price: 1.49 },
{ title: "Article 1", price: 3.00 },
{ title: "Article 4", price: 5.99 },
{ title: "Article 2", price: 19.99 }
]
function insertSorted (array, element, comparator) {
for (var i = 0; i < array.length && comparator(array[i], element) < 0; i++) {}
array.splice(i, 0, element)
}
function compareByPrice (a, b) { return a.price - b.price }
insertSorted(array, { title: "Article 5", price: 12.00 }, compareByPrice)
console.log(array)
&#13;
答案 1 :(得分:2)
如果它是一个很长的列表,您不希望每次都对列表进行排序。使用浮点数的排序最多为O(n * log n)。如果进行线性搜索,则会改为使用O(n)。
function search(a, v) {
if(a[0]['price'] > v['price']) {
return 0;
}
var i=1;
while (i<a.length && !(a[i]['price'] > v['price'] && a[i-1]['price'] <= v['price'])) {
i=i+1;
}
return i;
}
myArray.splice(search(myArray, newItem), 0, newItem)
但是,如果列表很长,那么进行二分搜索而不是线性搜索是个好主意。这将把它降低到O(log n)。二进制搜索非常简单。你从中间开始。如果元素大于您要搜索的元素,请将相同的算法应用于列表的上半部分,否则应用于下部。在网上找到二进制搜索的代码示例很容易。
以下是一个例子:
function binarySearch(ar, el, compare_fn) {
if (el.price < ar[0].price)
return 0;
if (el.price > ar[ar.length-1].price)
return ar.length;
var m = 0;
var n = ar.length - 1;
while (m <= n) {
var k = (n + m) >> 1;
var cmp = compare_fn(el, ar[k]);
if (cmp > 0) {
m = k + 1;
} else if(cmp < 0) {
n = k - 1;
} else {
return k;
}
}
return -m - 1;
}
function comp(a, b) {
return a['price']>b['price']
}
myArray.splice(binarySearch(myArray, element, comp), 0, element)
(从这里偷来Binary Search in Javascript)
但要把它包起来。添加元素然后排序通常是个坏主意。最好的情况是,它没关系,但既然你知道列表是排序的,为什么不至少做一个线性搜索呢?
如果列表很小,这没关系,但如果列表中有数百万个元素,那么差异就会非常明显。
编辑:
我做了一个快速而原始的基准。
10,000 100,000 1000,000 10,000,000
Sort 80 900 13000 N/A
Linear 2 2 25 5000
Binary 2 2 5 21
我测量了在四种不同尺寸上运行三种算法所花费的时间。我不想等待排序结束千万个元素。因此N / A.时间以毫秒为单位。请注意,基准测试非常原始,但它可以了解尺寸增长时它会产生多大影响。
答案 2 :(得分:1)
只需推送您的商品
var myArray = [
{ title: "Article 3", price: 1.49 },
{ title: "Article 1", price: 3.00 },
{ title: "Article 4", price: 5.99 },
{ title: "Article 2", price: 19.99 }
]
myArray.push({ title: "Article 5", price: 12.00 })
然后排序你的数组:
myArray.sort(function(a, b) {
return parseFloat(a.price) - parseFloat(b.price);
});
答案 3 :(得分:1)
我通过调整代码在Angular中实现了这一点。有人会觉得有用。
Array.prototype.sortedInsert = sortedInsert;
interface Array<T> {
sortedInsert(element: T, comparator: any): number;
}
/**
* This function takes an element, and a comparator function.
* It returns position of the inserted record.
*/
function sortedInsert<T>(element: T, comparatorFn: any): number {
const insertionIndex: number = findInsertionIndex(this, element, comparatorFn);
this.splice(insertionIndex, 0, element);
return insertionIndex;
}
function findInsertionIndex<T>(arr: Array<T>, element: T, comparatorFn: any): number {
if (arr.length === 0) {
return 0;
}
let low = 0;
let high: number = arr.length - 1;
while (low <= high) {
const mid: number = Math.floor(low + (high - low) / 2);
const comparison: number = comparatorFn(element, arr[mid]);
if (comparison === 0) {
return mid;
} else if (comparison < 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return low;
}
要使用此文件,您必须将此文件导入app.module.ts
。
用法示例:
const arr = [];
const comp = (a: number, b: number) => a - b;
arr.sortedInsert(2, comp);
arr.sortedInsert(1, comp);
arr.sortedInsert(3, comp);
console.log(arr);
答案 4 :(得分:0)
Update (Solution)
仍然无法正常运行。应该放在开头或结尾的项目放置在错误的位置,请参阅基于相同代码的修订版解决方案:
Array.prototype.pushSorted = function(el, compareFn) {
let index = (function(arr) {
var m = 0;
var n = arr.length - 1;
while(m <= n) {
var k = (n + m) >> 1;
var cmp = compareFn(el, arr[k]);
if(cmp > 0) m = k + 1;
else if(cmp < 0) n = k - 1;
else {
console.log(`m=${m} k=${k}`)
return k;
};
}
return -m - 1;
})(this);
if (index >= 0)
this.splice(index, 0, el);
else if (index < 0)
this.splice((index * -1) - 1, 0, el);
return this.length;
};
样品用量:
a = [1, 2, 3, 4, 5]
a.pushSorted(2.5, (a,b) => a - b);
a.pushSorted(8, (a,b) => a - b);
a.pushSorted(0.5, (a,b) => a - b);
答案 5 :(得分:0)
这是我当前的打字稿实现:
enum SortDirection {
Ascending,
Descending
}
const propertyComparer = <T>(
a: T,
b: T,
property: keyof T,
direction: SortDirection
): number => {
if (a[property] < b[property]) {
return direction === SortDirection.Ascending ? 1 : -1;
}
if (a[property] > b[property]) {
return direction === SortDirection.Ascending ? -1 : 1;
}
return 0;
};
const findAndInsertByProperty = <T>(
arr: T[],
item: T,
property: keyof T,
direction: SortDirection
): number => {
let start = 0;
let end = arr.length;
while (start < end) {
const mid = (start + end) >> 1;
const result = propertyComparer<T>(item, arr[mid], property, direction);
if (result === 0) {
return mid;
} else if (result < 0) {
end = mid;
} else {
start = mid + 1;
}
}
return end;
};
const myArray = [
{ title: "Article 3", price: 1.49 },
{ title: "Article 1", price: 3.00 },
{ title: "Article 4", price: 5.99 },
{ title: "Article 2", price: 19.99 }
];
const value = { title: "Article 5", price: 12.00 };
const valueLowest = { title: "Article 6", price: 0.49 };
const valueHighest = { title: "Article 7", price: 20.00 };
myArray.splice(findAndInsertByProperty(myArray, value, 'price', SortDirection.Descending), 0, value);
myArray.splice(findAndInsertByProperty(myArray, valueLowest, 'price', SortDirection.Descending), 0, valueLowest);
myArray.splice(findAndInsertByProperty(myArray, valueHighest, 'price', SortDirection.Descending), 0, valueHighest);
console.log(myArray);
答案 6 :(得分:-1)
不确定这是否是最佳的,但您可以将其推入另一个(重复的)数组,然后对其进行排序,然后检查其索引以便将其推送到正确的索引位置:
Array.prototype.pushSorted = function(value, compareFunction) {
const arrCopy = this.map(element => element);
arrCopy.push(value);
arrCopy.sort(compareFunction);
this.splice(arrCopy.indexOf(value), 0, value);
return this.length;
};
首先,我们创建一个数组实例的副本。然后将元素推入此数组副本。然后对数组副本进行排序。然后将元素推送(通过splice
方法)到实数数组中,同时检查数组副本中的索引。然后我们可以返回数组长度(就像普通的push
)。
示例:
const sortByPrice = (a, b) => a > b ? 1 : -1;
const newArticle = { title: "Article 5", price: 12.00 };
theArray.pushSorted(newArticle, sortByPrice);
答案 7 :(得分:-1)
考虑我的解决方案如下;
var articles=[
{ title: "Article 3", price: 1.49 },
{ title: "Article 1", price: 3.00 },
{ title: "Article 4", price: 5.99 },
{ title: "Article 2", price: 19.99 }
]
现在以这种方式写一个函数;
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key]; var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
现在插入一个元素;
articles.push({ title: "Article 5", price: 12.00 });
最后排序;
articles=sortByKey(articles, 'price');