代码之家  ›  专栏  ›  技术社区  ›  totalnoob

按模式排序数组-javascript

  •  3
  • totalnoob  · 技术社区  · 7 年前

    对于一组

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

    使用模式['one','two','three']将其转换为

    ['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 回复  |  直到 7 年前
        1
  •  1
  •   slider    7 年前

    我认为您的想法是正确的,但是您希望首先遍历模式数组以保持顺序,然后继续查找 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
  •   amrender singh    7 年前

    请尝试以下操作:

    • 计算模式中所有元素的频率。
    • 而不是简单地迭代模式数组并一个接一个地推动每个元素(直到每个元素计数为零)。

    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
  •   customcommander    7 年前

    这是一个有趣的问题!

    注意:您并不真正知道如何处理模式未知的元素。它们应该都出现在开头还是结尾,或者均匀分布?我已经决定忽略这一点。

    如果将模式视为生成新数组的种子,而不是对现有数组的迭代约束,那么问题更容易解决。

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

    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)
    
    );
        4
  •  0
  •   HMR    7 年前

    您应该改用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())));