2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -2,7 +2,7 @@ Given two sets of items then if any item is common to any set then the result of
|
|||
* The two input sets if no common item exists between the two input sets of items.
|
||||
* The single set that is the union of the two input sets if they share a common item.
|
||||
|
||||
Given N sets of items where N>2 then the result is the same as repeatedly replacing all combinations of two sets by their consolidation until no further consolidation between set pairs is possible.
|
||||
<br>Given N sets of items where N>2 then the result is the same as repeatedly replacing all combinations of two sets by their consolidation until no further consolidation between set pairs is possible.
|
||||
If N<2 then consolidation has no strict meaning and the input can be returned.
|
||||
|
||||
;'''Example 1:'''
|
||||
|
|
@ -16,6 +16,7 @@ If N<2 then consolidation has no strict meaning and the input can be returned.
|
|||
::<tt>{H,I,K}</tt>, <tt>{A,B}</tt>, <tt>{C,D}</tt>, <tt>{D,B}</tt>, and <tt>{F,G,H}</tt>
|
||||
:Is the two sets:
|
||||
::<tt>{A, C, B, D}</tt>, and <tt>{G, F, I, H, K}</tt>
|
||||
|
||||
'''See also:'''
|
||||
<br>
|
||||
'''See also'''
|
||||
* [[wp:Connected component (graph theory)|Connected component (graph theory)]]
|
||||
<br><br>
|
||||
|
|
|
|||
107
Task/Set-consolidation/C-sharp/set-consolidation.cs
Normal file
107
Task/Set-consolidation/C-sharp/set-consolidation.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SetConsolidation
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
var setCollection1 = new[] {new[] {"A", "B"}, new[] {"C", "D"}};
|
||||
var setCollection2 = new[] {new[] {"A", "B"}, new[] {"B", "D"}};
|
||||
var setCollection3 = new[] {new[] {"A", "B"}, new[] {"C", "D"}, new[] {"B", "D"}};
|
||||
var setCollection4 = new[] {new[] {"H", "I", "K"}, new[] {"A", "B"}, new[] {"C", "D"},
|
||||
new[] {"D", "B"}, new[] {"F", "G", "H"}};
|
||||
var input = new[] {setCollection1, setCollection2, setCollection3, setCollection4};
|
||||
|
||||
foreach (var sets in input) {
|
||||
Console.WriteLine("Start sets:");
|
||||
Console.WriteLine(string.Join(", ", sets.Select(s => "{" + string.Join(", ", s) + "}")));
|
||||
Console.WriteLine("Sets consolidated using Nodes:");
|
||||
Console.WriteLine(string.Join(", ", ConsolidateSets1(sets).Select(s => "{" + string.Join(", ", s) + "}")));
|
||||
Console.WriteLine("Sets consolidated using Set operations:");
|
||||
Console.WriteLine(string.Join(", ", ConsolidateSets2(sets).Select(s => "{" + string.Join(", ", s) + "}")));
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Consolidates sets using a connected-component-finding-algorithm involving Nodes with parent pointers.
|
||||
/// The more efficient solution, but more elaborate code.
|
||||
/// </summary>
|
||||
private static IEnumerable<IEnumerable<T>> ConsolidateSets1<T>(IEnumerable<IEnumerable<T>> sets,
|
||||
IEqualityComparer<T> comparer = null)
|
||||
{
|
||||
if (comparer == null) comparer = EqualityComparer<T>.Default;
|
||||
var elements = new Dictionary<T, Node<T>>();
|
||||
foreach (var set in sets) {
|
||||
Node<T> top = null;
|
||||
foreach (T value in set) {
|
||||
Node<T> element;
|
||||
if (elements.TryGetValue(value, out element)) {
|
||||
if (top != null) {
|
||||
var newTop = element.FindTop();
|
||||
top.Parent = newTop;
|
||||
element.Parent = newTop;
|
||||
top = newTop;
|
||||
} else {
|
||||
top = element.FindTop();
|
||||
}
|
||||
} else {
|
||||
elements.Add(value, element = new Node<T>(value));
|
||||
if (top == null) top = element;
|
||||
else element.Parent = top;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var g in elements.Values.GroupBy(element => element.FindTop().Value))
|
||||
yield return g.Select(e => e.Value);
|
||||
}
|
||||
|
||||
private class Node<T>
|
||||
{
|
||||
public Node(T value, Node<T> parent = null) {
|
||||
Value = value;
|
||||
Parent = parent ?? this;
|
||||
}
|
||||
|
||||
public T Value { get; }
|
||||
public Node<T> Parent { get; set; }
|
||||
|
||||
public Node<T> FindTop() {
|
||||
var top = this;
|
||||
while (top != top.Parent) top = top.Parent;
|
||||
//Set all parents to the top element to prevent repeated iteration in the future
|
||||
var element = this;
|
||||
while (element.Parent != top) {
|
||||
var parent = element.Parent;
|
||||
element.Parent = top;
|
||||
element = parent;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Consolidates sets using operations on the HashSet<T> class.
|
||||
/// Less efficient than the other method, but easier to write.
|
||||
/// </summary>
|
||||
private static IEnumerable<IEnumerable<T>> ConsolidateSets2<T>(IEnumerable<IEnumerable<T>> sets,
|
||||
IEqualityComparer<T> comparer = null)
|
||||
{
|
||||
if (comparer == null) comparer = EqualityComparer<T>.Default;
|
||||
var currentSets = sets.Select(s => new HashSet<T>(s)).ToList();
|
||||
int previousSize;
|
||||
do {
|
||||
previousSize = currentSets.Count;
|
||||
for (int i = 0; i < currentSets.Count - 1; i++) {
|
||||
for (int j = currentSets.Count - 1; j > i; j--) {
|
||||
if (currentSets[i].Overlaps(currentSets[j])) {
|
||||
currentSets[i].UnionWith(currentSets[j]);
|
||||
currentSets.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (previousSize > currentSets.Count);
|
||||
foreach (var set in currentSets) yield return set.Select(value => value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
open console
|
||||
open monad io
|
||||
|
||||
consolidate [['H','I','K'], ['A','B'], ['C','D'], ['D','B'], ['F','G','H']] |> writen $
|
||||
consolidate [['A','B'], ['B','D']] |> writen
|
||||
:::IO
|
||||
|
||||
do
|
||||
x <- return $ consolidate [['H','I','K'], ['A','B'], ['C','D'], ['D','B'], ['F','G','H']]
|
||||
putLn x
|
||||
y <- return $ consolidate [['A','B'], ['B','D']]
|
||||
putLn y
|
||||
|
|
|
|||
23
Task/Set-consolidation/Elixir/set-consolidation.elixir
Normal file
23
Task/Set-consolidation/Elixir/set-consolidation.elixir
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
defmodule RC do
|
||||
def set_consolidate(sets, result\\[])
|
||||
def set_consolidate([], result), do: result
|
||||
def set_consolidate([h|t], result) do
|
||||
case Enum.find(t, fn set -> not MapSet.disjoint?(h, set) end) do
|
||||
nil -> set_consolidate(t, [h | result])
|
||||
set -> set_consolidate([MapSet.union(h, set) | t -- [set]], result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
examples = [[[:A,:B], [:C,:D]],
|
||||
[[:A,:B], [:B,:D]],
|
||||
[[:A,:B], [:C,:D], [:D,:B]],
|
||||
[[:H,:I,:K], [:A,:B], [:C,:D], [:D,:B], [:F,:G,:H]]]
|
||||
|> Enum.map(fn sets ->
|
||||
Enum.map(sets, fn set -> MapSet.new(set) end)
|
||||
end)
|
||||
|
||||
Enum.each(examples, fn sets ->
|
||||
IO.write "#{inspect sets} =>\n\t"
|
||||
IO.inspect RC.set_consolidate(sets)
|
||||
end)
|
||||
47
Task/Set-consolidation/Perl/set-consolidation.pl
Normal file
47
Task/Set-consolidation/Perl/set-consolidation.pl
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use strict;
|
||||
use English;
|
||||
use Smart::Comments;
|
||||
|
||||
my @ex1 = consolidate( (['A', 'B'], ['C', 'D']) );
|
||||
### Example 1: @ex1
|
||||
my @ex2 = consolidate( (['A', 'B'], ['B', 'D']) );
|
||||
### Example 2: @ex2
|
||||
my @ex3 = consolidate( (['A', 'B'], ['C', 'D'], ['D', 'B']) );
|
||||
### Example 3: @ex3
|
||||
my @ex4 = consolidate( (['H', 'I', 'K'], ['A', 'B'], ['C', 'D'], ['D', 'B'], ['F', 'G', 'H']) );
|
||||
### Example 4: @ex4
|
||||
exit 0;
|
||||
|
||||
sub consolidate {
|
||||
scalar(@ARG) >= 2 or return @ARG;
|
||||
my @result = ( shift(@ARG) );
|
||||
my @recursion = consolidate(@ARG);
|
||||
foreach my $r (@recursion) {
|
||||
if (set_intersection($result[0], $r)) {
|
||||
$result[0] = [ set_union($result[0], $r) ];
|
||||
}
|
||||
else {
|
||||
push @result, $r;
|
||||
}
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
||||
sub set_union {
|
||||
my ($a, $b) = @ARG;
|
||||
my %union;
|
||||
foreach my $a_elt (@{$a}) { $union{$a_elt}++; }
|
||||
foreach my $b_elt (@{$b}) { $union{$b_elt}++; }
|
||||
return keys(%union);
|
||||
}
|
||||
|
||||
sub set_intersection {
|
||||
my ($a, $b) = @ARG;
|
||||
my %a_hash;
|
||||
foreach my $a_elt (@{$a}) { $a_hash{$a_elt}++; }
|
||||
my @result;
|
||||
foreach my $b_elt (@{$b}) {
|
||||
push(@result, $b_elt) if exists($a_hash{$b_elt});
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
|
@ -1,52 +1,52 @@
|
|||
/*REXX program demonstrates a method of consolidating some sample sets. */
|
||||
/*REXX program demonstrates a method of consolidating some sample sets. */
|
||||
@.=; @.1 = '{A,B} {C,D}'
|
||||
@.2 = "{A,B} {B,D}"
|
||||
@.3 = '{A,B} {C,D} {D,B}'
|
||||
@.4 = '{H,I,K} {A,B} {C,D} {D,B} {F,G,H}'
|
||||
@.5 = '{snow,ice,slush,frost,fog} {icebergs,icecubes} {rain,fog,sleet}'
|
||||
|
||||
do j=1 while @.j\=='' /*traipse through each of sample sets. */
|
||||
call SETconsolidate @.j /*have the function do the heavy work. */
|
||||
do j=1 while @.j\=='' /*traipse through each of sample sets. */
|
||||
call SETconsolidate @.j /*have the function do the heavy work. */
|
||||
end /*j*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────ISIN SUBRoutine───────────────────────────*/
|
||||
isIn: return wordpos(arg(1), arg(2))\==0 /*is (word) arg1 in set arg2 ? */
|
||||
/*──────────────────────────────────SETCONSOLIDATE subroutine─────────────────*/
|
||||
SETconsolidate: procedure; parse arg old,new; #=words(old) /*nullify NEW.*/
|
||||
say ' the old set=' space(old)
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
isIn: return wordpos(arg(1), arg(2))\==0 /*is (word) argument 1 in the set arg2?*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
SETconsolidate: procedure; parse arg old; #=words(old); new=
|
||||
say ' the old set=' space(old)
|
||||
|
||||
do k=1 for # /* [↓] change all commas to a blank. */
|
||||
!.k=translate(word(old,k), , '},{') /*create a list of words (aka, a set).*/
|
||||
end /*k*/ /* [↑] ··· and also remove the braces.*/
|
||||
do k=1 for # /* [↓] change all commas to a blank. */
|
||||
!.k=translate(word(old,k), , '},{') /*create a list of words (aka, a set).*/
|
||||
end /*k*/ /* [↑] ··· and also remove the braces.*/
|
||||
|
||||
do until \changed; changed=0 /*consolidate some sets (well, maybe).*/
|
||||
do set=1 for #-1
|
||||
do item=1 for words(!.set); x=word(!.set,item)
|
||||
do other=set+1 to #
|
||||
if isIn(x,!.other) then do; changed=1 /*has changed*/
|
||||
!.set=!.set !.other; !.other=
|
||||
iterate set
|
||||
end
|
||||
end /*other*/
|
||||
end /*item */
|
||||
end /*set */
|
||||
end /*until*/
|
||||
/* ╔╦══════════════════════════════════════════════════elide any duplicates.*/
|
||||
do set=1 for #; $= /*nullify $ */
|
||||
do items=1 for words(!.set); x=word(!.set, items)
|
||||
if x==',' then iterate; if x=='' then leave
|
||||
$=$ x /*build new. */
|
||||
do until \isIn(x, !.set)
|
||||
_=wordpos(x, !.set)
|
||||
!.set=subword(!.set,1,_-1) ',' subword(!.set,_+1) /*purify set.*/
|
||||
end /*until ¬isIn ··· */
|
||||
end /*items*/
|
||||
!.set=translate(strip($), ',', " ")
|
||||
end /*set*/
|
||||
do until \changed; changed=0 /*consolidate some sets (well, maybe).*/
|
||||
do set=1 for #-1
|
||||
do item=1 for words(!.set); x=word(!.set, item)
|
||||
do other=set+1 to #
|
||||
if isIn(x, !.other) then do; changed=1 /*it's changed*/
|
||||
!.set=!.set !.other; !.other=
|
||||
iterate set
|
||||
end
|
||||
end /*other*/
|
||||
end /*item */
|
||||
end /*set */
|
||||
end /*until ¬changed*/
|
||||
|
||||
do i=1 for #; if !.i=='' then iterate
|
||||
new=space(new '{'!.i"}")
|
||||
end /*i*/
|
||||
do set=1 for #; $= /*elide dups*/
|
||||
do items=1 for words(!.set); x=word(!.set, items)
|
||||
if x==',' then iterate; if x=='' then leave
|
||||
$=$ x /*build new. */
|
||||
do until \isIn(x, !.set)
|
||||
_=wordpos(x, !.set)
|
||||
!.set=subword(!.set, 1, _-1) ',' subword(!.set, _+1) /*purify set*/
|
||||
end /*until ¬isIn ··· */
|
||||
end /*items*/
|
||||
!.set=translate(strip($), ',', " ")
|
||||
end /*set*/
|
||||
|
||||
say ' the new set=' new; say
|
||||
return
|
||||
do i=1 for #; if !.i=='' then iterate /*ignore any set that is a null set. */
|
||||
new=space(new '{'!.i"}") /*prepend and append a set identifier. */
|
||||
end /*i*/
|
||||
|
||||
say ' the new set=' new; say
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
@(do
|
||||
(defun mkset (p x) (set [p x] (or [p x] x)))
|
||||
(defun mkset (p x) (set [p x] (or [p x] x)))
|
||||
|
||||
(defun fnd (p x) (if (eq [p x] x) x (fnd p [p x])))
|
||||
(defun fnd (p x) (if (eq [p x] x) x (fnd p [p x])))
|
||||
|
||||
(defun uni (p x y)
|
||||
(let ((xr (fnd p x)) (yr (fnd p y)))
|
||||
(set [p xr] yr)))
|
||||
(defun uni (p x y)
|
||||
(let ((xr (fnd p x)) (yr (fnd p y)))
|
||||
(set [p xr] yr)))
|
||||
|
||||
(defun consoli (sets)
|
||||
(let ((p (hash)))
|
||||
(each ((s sets))
|
||||
(each ((e s))
|
||||
(mkset p e)
|
||||
(uni p e (car s))))
|
||||
(hash-values
|
||||
[group-by (op fnd p) (hash-keys
|
||||
[group-by identity (flatten sets)])])))
|
||||
(defun consoli (sets)
|
||||
(let ((p (hash)))
|
||||
(each ((s sets))
|
||||
(each ((e s))
|
||||
(mkset p e)
|
||||
(uni p e (car s))))
|
||||
(hash-values
|
||||
[group-by (op fnd p) (hash-keys
|
||||
[group-by identity (flatten sets)])])))
|
||||
|
||||
;; tests
|
||||
;; tests
|
||||
|
||||
(each ((test '(((a b) (c d))
|
||||
((a b) (b d))
|
||||
((a b) (c d) (d b))
|
||||
((h i k) (a b) (c d) (d b) (f g h)))))
|
||||
(format t "~s -> ~s\n" test (consoli test))))
|
||||
(each ((test '(((a b) (c d))
|
||||
((a b) (b d))
|
||||
((a b) (c d) (d b))
|
||||
((h i k) (a b) (c d) (d b) (f g h)))))
|
||||
(format t "~s -> ~s\n" test (consoli test)))
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
@(do
|
||||
(defun mkset (items) [group-by identity items])
|
||||
(defun mkset (items) [group-by identity items])
|
||||
|
||||
(defun empty-p (set) (zerop (hash-count set)))
|
||||
(defun empty-p (set) (zerop (hash-count set)))
|
||||
|
||||
(defun consoli (ss)
|
||||
(defun comb (cs s)
|
||||
(cond ((empty-p s) cs)
|
||||
((null cs) (list s))
|
||||
((empty-p (hash-isec s (first cs)))
|
||||
(cons (first cs) (comb (rest cs) s)))
|
||||
(t (consoli (cons (hash-uni s (first cs)) (rest cs))))))
|
||||
[reduce-left comb ss nil])
|
||||
(defun consoli (ss)
|
||||
(defun combi (cs s)
|
||||
(cond ((empty-p s) cs)
|
||||
((null cs) (list s))
|
||||
((empty-p (hash-isec s (first cs)))
|
||||
(cons (first cs) (combi (rest cs) s)))
|
||||
(t (consoli (cons (hash-uni s (first cs)) (rest cs))))))
|
||||
[reduce-left combi ss nil])
|
||||
|
||||
;; tests
|
||||
(each ((test '(((a b) (c d))
|
||||
((a b) (b d))
|
||||
((a b) (c d) (d b))
|
||||
((h i k) (a b) (c d) (d b) (f g h)))))
|
||||
(format t "~s -> ~s\n" test
|
||||
[mapcar hash-keys (consoli [mapcar mkset test])])))
|
||||
;; tests
|
||||
(each ((test '(((a b) (c d))
|
||||
((a b) (b d))
|
||||
((a b) (c d) (d b))
|
||||
((h i k) (a b) (c d) (d b) (f g h)))))
|
||||
(format t "~s -> ~s\n" test
|
||||
[mapcar hash-keys (consoli [mapcar mkset test])]))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue