= array(); } $post['classname'] = 'post'; } function comment_format(&$post) { global $conf, $uid, $gid, $forumlist; if (empty($post)) return; $forum = $post['fid'] ? forum_read($post['fid']) : ''; $thread = well_thread_read_cache($post['tid']); if ($thread) { //$post['fid'] = $thread['fid']; $post['closed'] = $thread['closed']; $post['subject'] = $thread['subject']; $post['url'] = $thread['url']; } else { $post['closed'] = 0; $post['subject'] = lang('thread_not_exists'); $post['url'] = ''; } $post['create_date_fmt'] = humandate($post['create_date']); //$post['message'] = stripslashes(htmlspecialchars_decode($post['message'])); $user = user_read_cache($post['uid']); $post['username'] = array_value($user, 'username'); $post['user_avatar_url'] = array_value($user, 'avatar_url'); $post['user'] = $user ? user_safe_info($user) : user_guest(); isset($post['floor']) || $post['floor'] = 0; // 权限判断 $post['allowupdate'] = 2 == array_value($forum, 'comment', 0) && ($uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowupdate')); $post['allowdelete'] = group_access($gid, 'allowuserdelete') && $uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowdelete'); $post['user_url'] = url('user-' . $post['uid'] . ($post['uid'] ? '' : '-' . $post['pid'])); if ($post['files'] > 0) { list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($post['pid']); // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 if (2 == $conf['attach_on']) { foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $post['message'] = FALSE !== strpos($post['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $post['message']) : $post['message']; } } $post['filelist'] = $filelist; } else { $post['filelist'] = array(); } $post['classname'] = 'post'; } function comment_format_message(&$val) { global $conf; if (empty($val)) return; // 使用云储存 if (1 == $conf['attach_on'] && 1 == $val['attach_on']) { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } elseif (2 == $conf['attach_on'] && 2 == $val['attach_on']) { // 使用图床 list($attachlist, $imagelist, $filelist) = well_attach_find_by_tid($val['tid']); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $val['message'] = FALSE !== strpos($val['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $val['message']) : $val['message']; } } else { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } //$val['message'] = stripslashes(htmlspecialchars_decode($val['message'])); } // 把内容中使用了云储存的附件链接替换掉 function comment_message_replace_url($pid, $message) { global $conf; if (0 == $conf['attach_on']) { $message = FALSE !== strpos($message, '="../upload/') ? str_replace('="../upload/', '="upload/', $message) : $message; $message = FALSE !== strpos($message, '="/upload/') ? str_replace('="/upload/', '="upload/', $message) : $message; } elseif (1 == $conf['attach_on']) { // 使用云储存 $message = str_replace('="' . $conf['cloud_url'] . 'upload/', '="upload/', $message); } elseif (2 == $conf['attach_on']) { // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($pid); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换回相对链接 $message = $attach['image_url'] && FALSE !== strpos($message, $attach['image_url']) ? str_replace($attach['image_url'], $url, $message) : $message; } } return $message; } function comment_filter($val) { unset($val['userip']); return $val; } function comment_highlight_keyword($str, $k) { $r = str_ireplace($k, '' . $k . '', $str); return $r; } // //
function comment_message_format(&$s) { if (xn_strlen($s) < 100) return; $s = preg_replace('#.*?
#is', '', $s); $s = str_ireplace(array('
', '
', '
', '

', '', '', '', '' . ''), "\r\n", $s); $s = str_ireplace(array(' '), " ", $s); $s = strip_tags($s); $s = preg_replace('#[\r\n]+#', "\n", $s); $s = xn_substr(trim($s), 0, 100); $s = str_replace("\n", '
', $s); } // 对内容进行引用 function comment_quote($quotepid) { $quotepost = comment_read($quotepid); if (empty($quotepost)) return ''; $uid = $quotepost['uid']; $s = $quotepost['message']; $s = comment_brief($s, 100); $userhref = url('user-' . $uid); $user = user_read_cache($uid); $r = '
' . $user['username'] . ' ' . $s . '
'; return $r; } // 获取内容的简介 0: html, 1: txt; 2: markdown; 3: ubb function comment_brief($s, $len = 100) { $s = strip_tags($s); $s = htmlspecialchars($s); $more = xn_strlen($s) > $len ? ' ... ' : ''; $s = xn_substr($s, 0, $len) . $more; return $s; } ?>MapSet to maintain unique array of arrays, Javascript - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

MapSet to maintain unique array of arrays, Javascript - Stack Overflow

programmeradmin55浏览0评论

I am trying to build unique array of arrays such that whenever I have new array to add it should only add if it doesn't already exist in collection

E.g. store all unique permutations of [1,1,2]

Actual : [[1,1,2],[1,2,1],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]
Expected : [[1,1,2],[1,2,1],[2,1,1]]

Approaches I tried:

  1. Array.Filter: Doesn't work because arrays are object and each value in uniqueArrComparer is a unique object reference to that array element.
function uniqueArrComparer(value, index, self) {
  return self.indexOf(value) === index;
}

result.filter(uniqueArrComparer)
  1. Set/Map: Thought I can build a unique array set but it doesn't work because Set internally uses strict equality comparer (===), which will consider each array in this case as unique.
    We cannot customize object equality for JavaScript Set

  2. Store each array element as a string in a Set/Map/Array and build an array of unique strings. In the end build array of array using array of unique string. This approach will work but doesn't look like efficient solution.

Working solution using Set

let result = new Set();

// Store [1,1,2] as "1,1,2"
result.add(permutation.toString());

return Array.from(result)
  .map(function(permutationStr) {

    return permutationStr
      .split(",")
      .map(function(value) {

        return parseInt(value, 10);
      });
  });

I am trying to build unique array of arrays such that whenever I have new array to add it should only add if it doesn't already exist in collection

E.g. store all unique permutations of [1,1,2]

Actual : [[1,1,2],[1,2,1],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]
Expected : [[1,1,2],[1,2,1],[2,1,1]]

Approaches I tried:

  1. Array.Filter: Doesn't work because arrays are object and each value in uniqueArrComparer is a unique object reference to that array element.
function uniqueArrComparer(value, index, self) {
  return self.indexOf(value) === index;
}

result.filter(uniqueArrComparer)
  1. Set/Map: Thought I can build a unique array set but it doesn't work because Set internally uses strict equality comparer (===), which will consider each array in this case as unique.
    We cannot customize object equality for JavaScript Set

  2. Store each array element as a string in a Set/Map/Array and build an array of unique strings. In the end build array of array using array of unique string. This approach will work but doesn't look like efficient solution.

Working solution using Set

let result = new Set();

// Store [1,1,2] as "1,1,2"
result.add(permutation.toString());

return Array.from(result)
  .map(function(permutationStr) {

    return permutationStr
      .split(",")
      .map(function(value) {

        return parseInt(value, 10);
      });
  });

This problem is more of a learning exercise than any application problem.

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked May 4, 2017 at 1:14 RohitRohit 6,60316 gold badges64 silver badges92 bronze badges 1
  • 1 As you've gathered, there's no built-ins that will work with this particular setup where arrays inside an array need to be checked, not just the values, but the order as well. You'd have to roll your own, and that would mean either stringifying the arrays and checking the strings, or just checking each array individually agains the new array. – adeneo Commented May 4, 2017 at 1:19
Add a comment  | 

6 Answers 6

Reset to default 38

One way would be to convert the arrays to JSON strings, then use a Set to get unique values, and convert back again

var arr = [
  [1, 1, 2],
  [1, 2, 1],
  [1, 1, 2],
  [1, 2, 1],
  [2, 1, 1],
  [2, 1, 1]
];

let set  = new Set(arr.map(JSON.stringify));
let arr2 = Array.from(set).map(JSON.parse);

console.log(arr2)

The fastest method I've found is:

const points = [
  [0,0],
  [100,100],
  [400,400],
  [200,200],
  [200,200],
  [200,200],
  [300,300],
  [400,400],
]

const uniquePoints = Array.from(
  new Map(points.map((p) => [p.join(), p])).values()
)

All of the methods in this thread are fast. This one is faster than the Set method, however, as we never need to convert the stringified array back into a array.

To find unique objects, replace p.join() with JSON.stringify(p).

Note

In my case, the method shown above turned out to be the wrong strategy, as I was only really needing to check against identical adjacent points. For example, the test array used above includes the value [400,400] two times, though these values are not consecutive. The method shown above would have removed the second instance, while the code below would have kept it.

points = points.filter(
    (point, i) =>
      i === 0 ||
      !(points[i - 1][0] === point[0] && points[i - 1][1] === point[1])
  )

If you are ok to use a library, try lodash uniqWith. This will recursively find groups of arrays OR objects with the comparator of your choice: equal in your case.

var arrayofarrays = [ [1,1,2], [1,2,1], [1,1,2], [1,2,1], [2,1,1], [2,1,1] ]

const uniqarray = _.uniqWith(arrayofarrays, _.isEqual);

console.log(uniqarray) //=> [[1, 1, 2], [1, 2, 1], [2, 1, 1]]

Bonus: it works on array of objects too

var objects = [{ 'x': 1, 'y': {b:1} }, { 'x': 1, 'y': {b:1} }, 
               { 'x': 2, 'y': {b:1} }, { 'x': 1, 'y': 2 }     ];

const uniqarray = _.uniqWith(objects, _.isEqual);

console.log(uniqarray) 
// => [{x: 1, y: {b: 1}}, {x: 2, y: {b: 1}}, {x: 1, y: 2}]

To get around the problem of each array being a unique object, you can stringify it so it's no longer unique, then map it back to an array later. This should do the trick:

var arr = [
  [1, 1, 2],
  [1, 2, 1],
  [1, 1, 2],
  [1, 2, 1],
  [2, 1, 1],
  [2, 1, 1]
];


var unique = arr.map(cur => JSON.stringify(cur))
  .filter(function(curr, index, self) {
    return self.indexOf(curr) == index;
  })
  .map(cur => JSON.parse(cur))

console.log(unique);

You can subclass Set for more flexibility in storing objects by storing the result of calling JSON.stringify on added objects.

class ObjectSet extends Set{
  add(elem){
    return super.add(typeof elem === 'object' ? JSON.stringify(elem) : elem);
  }
  has(elem){
    return super.has(typeof elem === 'object' ? JSON.stringify(elem) : elem);
  }
}
let set = new ObjectSet([[1,1,2],[1,2,1],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]);
console.log([...set]);
console.log([...set].map(JSON.parse));//get objects back

This answer uses reduce and find to check each of the values in the arrays.

const arr = [
  [1, 1, 2],
  [1, 2, 1],
  [1, 1, 2],
  [1, 2, 1],
  [2, 1, 1],
  [2, 1, 1]
];

const result = arr.reduce((unique, a) =>
  (unique.find(el => el[0] === a[0] && el[1] === a[1] && el[2] === a[2]) ?
    unique : [...unique, a]), []);

console.log(result);

references:

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
发布评论

评论列表(0)

  1. 暂无评论