按模式对数组进行排序-JavaScript

时间:2018-10-24 04:03:05

标签: javascript

对于

的数组
['one', 'one', 'two', 'two',  'three', 'one']

使用模式['one','Two','3']将其转换为

['one', 'two', 'three', 'one', 'two', 'one']

我的想法是

const sortArray = oldArray => {
let newArr = [];

while (newArr < oldArray.length) {
    // loop through array
    for (let i = 0; i < arr.length; i++) {
        // loop through pattern
        for (let j = 0; j < pattern.length; j++) {
            // match
            if (arr[i] === pattern[j]) {
                // add item to new array
                newArr.push(arr[i]);
                // remove item from old array
                arr.shift();
            } else {
                // push item to end of array
                arr.push(arr[i]);
                // remove item from array
                arr.shift()
            }
        }
    }
}

    return newArray;
}

我可以使用地图来做到这一点,这是我习惯于解决类似问题的方法,但是当涉及到仅通过具有模式的数组进行迭代时,我会感到非常困惑。有什么建议吗?

有地图,这就是我要做的

let a = ['one', 'one', 'two', 'two',  'three', 'one'];

const printValues = (arr, pattern) => {
  let map = {};
  let a = [];

  arr.forEach((v) => {
    if (!map[v]) map[v] = 1;
    else map[v]++;
  })

  while (a.length !== arr.length) {
    pattern.forEach((v) => {
      if (map[v] > 0) {
        a.push(v);
        map[v]--;
      }
    })
  }

  console.log(a);
}

console.log(printValues(a, ['one', 'two', 'three']))

5 个答案:

答案 0 :(得分:2)

这是一种无需使用Set或Object并考虑边缘情况(数组中的项不属于模式的项)的方法。

let items = ['one', 'one', 'two', 'two',  'three', 'one', 'three', 'xyz'];
let pattern = ['one', 'two', 'three'];

const sequence = (items, pattern) => {
  let results = [];
  // clean up the array
  let arr = items.map(item => pattern.includes(item) ? item : '').filter(x => x);
  while(arr.length) {
    pattern.forEach(x => {
      if (arr.includes(x)) {
        // add to results
        results.push(x);
        // remove item from the array
        arr.splice(arr.indexOf(x), 1);
      }
    })
  }
  return results;
}

sequence(items, pattern);

答案 1 :(得分:1)

我认为您有正确的主意,但您想首先遍历模式数组以保留顺序,然后继续查看oldArray。在以下解决方案中,我还将使用一组存储已使用的索引。

const oldArray = ['one', 'one', 'two', 'two', 'three', 'one'];
const pattern = ['one', 'two', 'three'];

let newArray = [];
let added = new Set();

while (newArray.length < oldArray.length) {
  for (let p of pattern) {
    for (let i = 0; i < oldArray.length; i++) {
      if (!added.has(i) && oldArray[i] === p) {
        added.add(i);
        newArray.push(p);
        break;
      }
    }
  }
}
console.log(newArray);

答案 2 :(得分:1)

尝试以下方法:

  • 计算模式中所有元素的频率。
  • 比简单地遍历模式数组并继续将每个元素一一推送(直到每个元素计数为零)。

let arr = ['one', 'one', 'two', 'two',  'three', 'one','three'];
let freq = arr.reduce((a,curr)=>{
  a[curr] = (a[curr] || 0)+1;
  return a;
},{});
let len =  Object.keys(freq).length;
let result = [];
let pattern = ["one", "two", "three"];
let i = 0;

while(len){
  if(freq[pattern[i]]){
    result.push(pattern[i]);
    freq[pattern[i]] --;
  } else
    len--;
  i++;
  i = i % pattern.length;
}
console.log(result);

答案 3 :(得分:1)

其他答案接近,但如果使用Map,则不需要模式数组。添加密钥的顺序就是可以将其取出的顺序。

您应该改用Map:

const arr = ['one', 'one', 'two', 'two', 'three', 'one'];
const map = arr.reduce(
  (result, item) =>
    result.set(item, (result.get(item) || []).concat(item)),
  new Map(),
);
const transform = (arr) => {
  const recur = (arr, result, index, max) => {
    if (index === max) {
      return result;
    }
    return recur(
      arr,
      result.concat(arr.map((item) => item[index])),
      index + 1,
      max,
    );
  };
  return recur(
    arr,
    [],
    0,
    Math.max(...arr.map((item) => item.length)),
  ).filter((x) => x !== undefined);
};
console.log(transform(Array.from(map.values())));

答案 4 :(得分:1)

这是一个有趣的问题!

注意:您实际上并没有告诉您如何处理模式未知的元素。它们应该全部出现在开头还是结尾,或者分布均匀?我已经决定不去理会。

如果您将模式看作是产生新数组的种子,而不是对现有数组的迭代约束,则此问题更容易解决,恕我直言。

您可以创建一个接受模式以及每个元素的频率的函数:

createFromPattern({one: 3, two: 2, three:1}, ['one', 'two', 'three']);

生成频率很容易:

const count = list => list.reduce((acc, cur) => ({...acc, [cur]: (acc[cur] || 0) + 1}), {});
count(['one', 'one', 'two', 'two',  'three', 'one']);
//=> { one: 3, two: 2, three: 1 }

让我们想象一下该功能的工作原理:

  1. { one: 3, two: 2, three: 1 }〜> ['one', 'two', 'three']
  2. { one: 2, two: 1, three: 0 }〜> ['one', 'two']
  3. { one: 1, two: 0, three: -1 }〜> ['one']
  4. { one: 0, two: -1, three: -2 }〜> [] 停止

如果汇总每个中间结果,则会得到最终数组。这可以递归完成:

const createFromPattern = (opts, seed) => {
  const newOpts = {...opts};
  const pick = seed.reduce((acc, cur) => [...acc, ...(newOpts[cur] ? newOpts[cur]-- && [cur] : [])], []);
  const stop = Math.max(...Object.values(newOpts)) <= 0;
  return [].concat(pick, (!stop ? createFromPattern(newOpts, seed) : []));
};

完全将其放入:

const list = ['one', 'one', 'two', 'two',  'three', 'one']
const pattern = ['one', 'two', 'three']

const count = list => list.reduce((acc, cur) => ({...acc, [cur]: (acc[cur] || 0) + 1}), {});

const createFromPattern = (opts, seed) => {
  const newOpts = {...opts};
  const pick = seed.reduce((acc, cur) => [...acc, ...(newOpts[cur] ? newOpts[cur]-- && [cur] : [])], []);
  const stop = Math.max(...Object.values(newOpts)) <= 0;
  return [].concat(pick, (!stop ? createFromPattern(newOpts, seed) : []));
};

console.log(

  createFromPattern(count(list), pattern)

);