通过对象键将数组项移至前面

15

所以我有一个对象数组;

[
    {
        "foo": 2,
        "bar": "test"
    },
    {
        "foo": 19,
        "bar": "value"
    },
    {
        "foo": 7,
        "bar": "temp"
    }
]

我需要将一个具有特定值 foo 的对象移动到数组的开头。该值始终在对象中,但不能保证该对象在数组中。

因此,在运行 moveToFront(19); 之后,我会得到以下结果:

[
    {
        "foo": 19,
        "bar": "value"
    },
    {
        "foo": 2,
        "bar": "test"
    },
    {
        "foo": 7,
        "bar": "temp"
    }
]

我该如何着手做这件事?


可能有比数组更好的数据结构,您的要求是什么?您想做什么?根据您需要多频繁地移动这个数组以及它的大小,这可能会很快变得昂贵。 - James
为什么?你想做什么让你认为需要移动数组中的元素? - Mike 'Pomax' Kamermans
数组前面的对象有什么用途? - Kyle Pittman
https://dev59.com/KG435IYBdhLWcg3woRnG - gurvinder372
1
值始终在对象中,但不能保证对象将在数组中。嗯? - Matt Burland
查看 array.aplice https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/splice - Zak
5个回答

15

这应该是相当简单的,你搜索数组直到找到你要查找的项,然后将其splice出来,并将其unshift回到开头。像这样:

// foo is the target value of foo you are looking for
// arr is your array of items
// NOTE: this is mutating. Your array will be changed (unless the item isn't found)
function promote(foo, arr) {
    for (var i=0; i < arr.length; i++) {
        if (arr[i].foo === foo) {
            var a = arr.splice(i,1);   // removes the item
            arr.unshift(a[0]);         // adds it back to the beginning
            break;
        }
    }
    // Matching item wasn't found. Array is unchanged, but you could do something
    // else here if you wish (like an error message).
}

如果没有与匹配的foo值相对应的项,则这不会对您的数组产生任何影响。如果需要,您可以通过错误消息来处理此问题。

你好。很好的答案!你知道一种方法可以不改变原始数组吗? - Yaya

14

最短的方法:Array.some

some() 方法测试数组中是否至少有一个元素通过提供的函数实现的测试。它返回一个布尔值。

请注意,Array.find 也会在找到目标后结束迭代,但它不支持 IE

var data = [{"foo":2}, {"foo":19}, {"foo":7}, {"foo":22}]

// if {foo:7} is found, move it to the front and break iteration
data.some((item, idx) => 
  item.foo == 7 && 
  data.unshift( 
    // remove the found item, in-place (by index with splice), 
    // returns an array of a single item removed
    data.splice(idx,1)[0] 
  ) 
)


// print result
console.log(data)

如果您不想改变原始数组,可以这样做:

如果您不想改变原始数组,可以这样做:

var data = [{"foo":2}, {"foo":19}, {"foo":7}, {"foo":22}]

// if {foo:7} is found, move it to to the front and break iteration 
const clonedData = [...data]
clonedData.some((item, i, arr) => item.foo == 7 && arr.unshift(item))

// print result
console.log(clonedData)


findIndex 方法可能会有帮助

The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test.

var data = [{"foo":2}, {"foo":19}, {"foo":7}, {"foo":22}]

// find the index of the target array item:
var itemIndex = data.findIndex(item => item.foo == 7); 

data.splice(
    0,                           // new index,
    0,                           // no removal
    data.splice(itemIndex, 1)[0] // detach the item and return it
);

// print result
console.log(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

If you use lodash and need to have legacy browsers support, use the _.findIndex method:

_.findIndex(data, {foo:19});

这将把键为"foo": 19的数组对象移动到数组的开头。


2
它不是移动,而是复制。最终你会得到5个项目。在最后,你可以使用data.pop() - Batman
@Batman - 在这两个例子中都没有复制。你的说法是不正确的。unshiftsplice会进行原地修改 - vsync

1
你可以迭代数组,找到正确的元素,对其进行切片,并将其余部分连接到被切片的数组中。
var collection = [
  {
    foo: 15,
    bar: true
  },
  {
    foo: 19,
    bar: false
  }
];

function moveToFront(x) {
  for (var i = 0; i < collection.length; i++) {
    if (collection[i].foo === x) {
      collection = collection.splice(i, 1).concat(collection);
      break;
    }
  }
}

moveToFront(19);

console.log(collection);

2
请注意,这也是复制而不是改变原始数组。 - Matt Burland

0

在每个属性中搜索任何值,第一个匹配成功即停止。由于使用了“some”方法并且在满足条件时打断了对数组的迭代,所以似乎非常快速。

'some'会为数组中存在的每个元素执行回调函数,直到找到其中一个返回true的元素。如果找到这样的元素,则some()将立即返回true。变异是就地完成的...

var collection = [
    {
        "foo": 2,
        "bar": "test"
    },
    {
        "foo": 19,
        "bar": "value"
    },
    {
        "foo": 7,
        "bar": "temp"
    }
];


function moveToFront(searchValue) {

    var idx, exists;

    for (idx = 0; idx < collection.length; idx++) {
            exists = Object.keys(collection[idx]).some(function (key) {
            return collection[idx][key] === searchValue
        });
        if (exists) break;
    }

    collection.unshift(collection[idx]);
    collection.splice(idx + 1, 1);

}

moveToFront("temp"); // or moveToFront(19); or move whatever
console.log(collection);

0

另一种解决方案。原地突变...

var collection = [
    {
        "foo": 2,
        "bar": "test"
    },
    {
        "foo": 19,
        "bar": "value"
    },
    {
        "foo": 7,
        "bar": "temp"
    }
];


function moveToFront(property, value, col) {
    col.reduce(function (prev, current, idx, obj) {
        if (current[property] != value) {
            return obj;
        } else {
            obj.unshift(obj[idx]);
            obj.splice(idx + 1, 1);
        }
    });
}

moveToFront('foo', 7, collection);
console.log(collection);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接