减少数组列表,以设置公共路径

时间:2018-07-09 08:08:46

标签: javascript node.js

我正在尝试将列表缩小为较短的列表,只是普通文件系统路径。试图找到所有普通的祖父母,并只将其列入最终名单。这是目标 目标是我们必须消除列表中所有包含父目录的目录。

一种更好的短语表达方式可能是: 目标是我们必须消除列表中存在该路径的父目录的所有路径。

说我有这个输入和预期的输出:

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

const output = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
];

const getReducedList = function (input) {

  return input
  .sort((a, b) => (a.length - b.length))
  .reduce((a, b) => {

    // console.log('a:', a, 'b:', b);

    const s = !a.some(v => {
      return b.startsWith(v);
    });

    if (s) {
      a.push(b);
    }

    return a;

  }, []);

};

console.log(getReducedList(input));

getReducedList函数似乎可以在我们的第一个测试用例中使用,将5减少到2。但是,如果我们添加第二个测试用例,这将变得很奇怪: < / p>

如果我从原始列表中删除了一个项目,并将其更改为以下4个列表:

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

然后我期望得到此输出(4个相同的列表):

const output = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

之所以我希望/希望使用相同的4,是因为列表中没有项目在列表中的其他位置具有父目录。但是我实际上得到的输出是2的列表,这是不正确的:

const output =  [ 
   '/home/oleg/WebstormProjects/oresoftware/r2g',
   '/home/oleg/WebstormProjects/oresoftware/sumanjs/suman' 
];

有人知道我该如何解决这个问题以获得预期的结果吗?一个答案需要同时满足两个测试用例。

为清楚起见,如果将"/home/oleg"添加到原始列表,则"/home/oleg"应该是输出中的唯一条目。

8 个答案:

答案 0 :(得分:2)

我认为您可以使用非常简单的递归函数来完成此操作。您只需按长度排序,然后递归弹出最短的字符串,将其添加到结果中,使用该值过滤数组,然后递归:

const input = [
    "/home/oleg/WebstormProjects/oresoftware/r2g",
    "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
    "/home/oleg/WebstormProjects/oresoftware/sumanjs",
    "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
    "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
  ];
  
input.sort((a,b) => b.length - a.length)
function getPrefixes(list, res =[]) {
    if (list.length < 1) return res
    let next = list.pop()
    res.push(next)
    return getPrefixes(list.filter(u => !u.startsWith(next + '/')), res)

}
console.log(getPrefixes(input))

答案 1 :(得分:1)

您可以添加斜线用于查找,并在下一个元素中找到时弹出最后一个值。

该提案使用按值排序的列表,而不是按字符串的长度,因为它需要一个排序后的列表来补偿下一个元素。

function uniqueFolder(array) {
    return array
        .sort()
        .reduce((a, b) => {
            if (b.startsWith(a[a.length - 1] + '/')) {
                a.pop();
            }
            a.push(b);
            return a;
        }, []);
}

function commonPath(array) {
    return array
        .sort()
        .reduce((a, b) => {
            if (!b.includes(a[a.length - 1])) {
                a.push(b);
            }
            return a;
        }, []);
}

const input = [ "/home/oleg/WebstormProjects/oresoftware/r2g", "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman", "/home/oleg/WebstormProjects/oresoftware/sumanjs", "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types", "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"];

console.log(uniqueFolder(input));
console.log(commonPath(input));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

您可以简单地使用节点的path模块

const path = require('path');
const input = [
  '/home/oleg/WebstormProjects/oresoftware/r2g',
  '/home/oleg/WebstormProjects/oresoftware/sumanjs/suman',
  '/home/oleg/WebstormProjects/oresoftware/sumanjs',
  '/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types',
  '/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch'
];

const s = new Set();
const out = [];
input.forEach(e => {
  let p = path.dirname(e);
  if (! s.has(p)) {
    s.add(p);
    out.push(e);
  }
});

console.log(out);

如果您想...,forEach显然可以用reduce代替...

答案 3 :(得分:1)

当下一个值在前一个值之后没有 last 前斜杠时,您需要避免匹配。

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

const getReducedList = (set => input => input.filter(b => 
     !set.has(b.substr(0, b.lastIndexOf("/")))))(new Set(input));

console.log(getReducedList(input));

逻辑是将所有路径放入集合中,然后检查每个路径的父路径是否在集合中。路径的父级是具有所有字符的路径,直到最后一个/为止(不包括最后一个字符)。

从输入中删除第二个条目不会更改输出。 sumansuman-typessuman-watch的处理方式相同。

这是更详细的ES5版本(用普通对象替换Set):

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

function getReducedList(input) {
    var hash = {};
    input.forEach(function(path) {
        hash[path] = true;
    });
    return input.filter(function (b) {
        return !hash[b.substr(0, b.lastIndexOf("/"))];
    }, []);
}

console.log(getReducedList(input));

答案 4 :(得分:1)

它虽然没有其他缺点,但仍无法进行排序。

编辑:必须添加排序才能正常工作

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

const input2 = [
  "/home/oleg/WebstormProjects/oresoftware",
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch"
];

function getParents(input) {
  return input.sort((a, b) => a.length - b.length)
  .reduce((acc, a) => {
    const index = acc.findIndex(b => b.startsWith(a) || a.startsWith(b));
    const slashDiff = index > 0 ? a.split('/').length === acc[index].split('/').length : false;
    if (index === -1 || slashDiff) {
      return [...acc, a];
    }
    acc.splice(index, 1, a.length < acc[index].length ? a : acc[index])

    return acc;
  }, []);

}

console.log(getParents(input));
console.log(getParents(input2));

答案 5 :(得分:1)

看起来我们只需要更改一行即可。这是原始文件:

const getReducedList = function (input) {

  return input
  .sort((a, b) => (a.length - b.length))
  .reduce((a, b) => {

    const s = !a.some(v => {
      return b.startsWith(v);
    });

    if (s) {
      a.push(b);
    }

    return a;

  }, []);

};

我们需要改为一行:

return b.startsWith(v + '/');

答案 6 :(得分:0)

如果可以使用es6中的集合,则可以根据目录长度进行排序,然后继续推送到集合。

答案 7 :(得分:0)

const input = [
  "/home/oleg/WebstormProjects/oresoftware/r2g",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-watch",
  "/home/oleg/WebstormProjects/oresoftware/sumanjs/suman-types-blabla",

];

let ouput = input.sort().reduce((a, c)=> {
let d = true;
for (let j =0; j< a.length; j++){
  if(c.startsWith(a[j]+'/')) {
  d=false;
  break;}
}
if (d) a.push(c);
return a;
},[]);

console.log(ouput);