重新排序对象数组,以便数组的每个位置都具有特定的键/值对

时间:2015-01-22 17:21:15

标签: javascript arrays sorting

我有一个对象数组,看起来像这样:

var players = [
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": '',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": 'test',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": '',
    "imagePos4": 'test'
  },
  {
    "imagePos1": 'test',
    "imagePos2": '',
    "imagePos3": 'test',
    "imagePos4": ''
  }
];

我需要重新组织player数组,以便0索引处的项目具有' imagePos1'的值。键,1索引处的项目具有' imagePos2'的值。键,以及第四项的开始和结束。因此,对于上面的数组,正确的输出将是:

var players = [
  {
    "imagePos1": 'test', // index 0
    "imagePos2": '',
    "imagePos3": 'test',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test', // index 1
    "imagePos3": '',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": 'test', // index 2
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": '',
    "imagePos4": 'test' // index 3
  }
];

我不知道数组中的对象之前会是什么样子,所以我还需要考虑这种对象无法以这种方式排序并输出一些的可能性消息。

这是我到目前为止所做的事情(我知道这太可怕了):

var objCache = {};
var noInfiniteLoopsPlz = 0;

function findDuds() {
  if (noInfiniteLoopsPlz > 256) { 
    console.log('aint gonna happen')
    return false;
  } else {
    // add one to this to make sure the recursive func doesn't go forever
    noInfiniteLoopsPlz++
    for (var i = 0; i < players.length; i++) {
      // find what images don't have the image needed
      if (players[i]['imagePos' + (i + 1)].length === 0) { 
        // find what ones do
        for (var j = 0; j < players.length; j++) {
          // when you find an image...
          if (players[i]['imagePos' + (j + 1)].length) {
            // save the object that's currently in that spot for now
            objCache = players[j];
            // then put the object that you're moving in its place
            players[j] = players[i];

            // place the saved object where the old one was
            players[i] = objCache;
            // see if the saved object has an image for the place that has opened up. If it hasn't, start this all over again
            if (objCache['imagePos' + (i + 1)].length) {
              findDuds();
            }
          }
        }
      }
    } 
  }
}

findDuds();


console.log(players);

2 个答案:

答案 0 :(得分:1)

根据您的输入数据,我们可以简单地执行以下操作。假设空值表示为空字符串;如果需要,你可以修改支票。

var players = [{
  "imagePos1": '',
  "imagePos2": 'test',
  "imagePos3": '',
  "imagePos4": ''
}, {
  "imagePos1": '',
  "imagePos2": 'test',
  "imagePos3": 'test',
  "imagePos4": ''
}, {
  "imagePos1": '',
  "imagePos2": 'test',
  "imagePos3": '',
  "imagePos4": 'test'
}, {
  "imagePos1": 'test',
  "imagePos2": '',
  "imagePos3": 'test',
  "imagePos4": ''
}];

//Make choices binary, store as ints, create possible combination parts
var bin = [];
var com = [];
for (var i in players) {
    bin[i] = 0;
    com[i] = [];
    for (prop in players[i]) {
        bin[i] <<= 1;
        bin[i] += ~~(players[i][prop].length > 0);
    }
    //Too lazy to write reasonably readable loops
    for (var j = 0, n = bin[i]; n; j++, n >>= 1) {
        if (n & 1) {
            com[i].push(1 << j);
        }
    }
}

//The object keys part is essentially just telling us how many properties there are, we could hardcode this or whatever
var v = (1 << Object.keys(players[0]).length) - 1;
var per = [];
var match;
var max = com.length - 1;
//Create all combinations of the above
var rec = function(a, i) {
    for (var j in com[i]) {
        var cpy = a.slice();
        cpy.push(com[i][j]);
        if (i < max) {
            rec(cpy, i + 1);
        } else {
            //We have a full combination, check if it fits
            var n = cpy[0];
            for (var j = 1; j < cpy.length; j++) {
                n |= cpy[j];
            }
            //Stop at first match, you can change this if you want all matches
            if (n === v) {
                match = cpy;
                return;
            }
        }
    }
}
rec([], 0);

//This is just for pretty-printing
if (match === void 0) {
    alert('there is no matching combination');
} else {
    var out = '';
    for (var i = 0; i < match.length; i++) {
        for (var j = 0; match[i] < v; match[i] <<= 1, j++) {
            //Empty loop body because snafucate
        }
        //Make both indexes 1-based for clarity
        out += 'element ' + (i + 1) + ' goes to slot ' + j + '; ';
    }
    alert(out);
}

答案 1 :(得分:0)

你想要找到满足一系列约束条件的玩家的排列。

如果从正确答案和池中删除第一个播放器,则正确答案的其余部分是满足类似约束集的池的排列。序列也很小。所以,我们可以使用递归搜索。

对于每个比第1位的玩家而言,我们看看是否存在从2到4的剩余玩家的排列。如果存在,我们返回候选者加上该排列。如果没有,将抛出异常,我们继续前进到下一个候选人。如果没有候选人,或者我们全部尝试过,那么问题就无法解决。对位置2的测试是类似的,因此代码是相同的。

var players = [
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": '',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": 'test',
    "imagePos4": ''
  },
  {
    "imagePos1": '',
    "imagePos2": 'test',
    "imagePos3": '',
    "imagePos4": 'test'
  },
  {
    "imagePos1": 'test',
    "imagePos2": '',
    "imagePos3": 'test',
    "imagePos4": ''
  }
];

/*
 * Returns a function which tests whether the player passed to it has
 * an image in the given position.
 */
function has(index) {
    return function (player) {
        return player["imagePos"+index];
    }
}

/*
 * Orders elements in `rest` numbered from from to `to`.
 * `start` is prepended.
 */
function order(from, to, start, rest) {
    /* check if we are done */
    if (from > to) {
        return start;
    }

    /* find elements that might come next */
    var candidates = rest.filter(has(from));

    var len = candidates.length;

    /* Try each candidate. */
    for (var i = 0; i < len; i++) {
        var candidate = candidates[i],
            /* elements that may come later assuming this candidate comes next */
            remainder = rest.filter(function (el) { return el !== candidate; }),
            /* new prefix including this candidate */
            newStart = start.concat(candidate);
        try {
            /* order the remaining candidates by the rest of the numbers */
            return order(1+from, to, newStart, remainder);
        } catch (e) {
            /* on failure we try the next candidate */
        }
    }

    /* If we get here we tried all the candidates (possibly 0) and none of them worked. */
    throw "unsatisfiable";
}

order(1, 4, [], players);