所以我正在研究一个问题,然后碰到一堵我似乎无法找到解决办法的墙。我从操作系统那里得到了很多信息,我想我会在这里问一下,看看有没有办法比我找到的更好。 基本上,我有一个类中包含一堆值,但出于我们的目的,只有一个重要。
public class GroupPair
{
public string object1 { get; set; }
public string object2 { get; set; }
public List<string> BothObjects
{
get
{
List<string> s= new List<string>();
s.Add(object1);
s.Add(object2);
return s;
}
}
我有一个List,我需要能够将它们分组。变得棘手的是两个值都不是唯一的,并且组的大小和组的数量是可变的。我基本上需要一种方式来说,“给我每个可以从这个列表组成的组,其中每个组包含所有包含该组的任何个体成员的对。”让我举几个例子......这里有一些对:
a d
f h
d t
n w
h a
n o
q d
w f
o y
分组后,这就是我想要的:
Group 1
a d
h a
q d
f h
w f
d t
Group 2
n x
n o
o y
融化你的大脑了吗? 关于如何做到这一点的任何想法,或者即使我可以自己研究这种概念的名称?
答案 0 :(得分:1)
这是我快速而肮脏的方法。
简短说明:
我们的想法是从一对开始(可以将其视为图中的节点)。从该节点添加任何相邻节点(具有共享成员的对)。然后搜索刚刚添加的节点旁边的节点。您一直跟踪已访问过的节点,因此您无法循环播放。
public static List<HashSet<GroupPair>> GetGroups(IEnumerable<GroupPair> pairs)
{
var groups = new List<HashSet<GroupPair>();
var unassignedPairs = new HashSet<GroupPair>(pairs);
while (unassignedPairs.Count != 0)
{
var group = new HashSet<GroupPair>();
var rootPair = unassignedPairs.First();
group.Add(rootPair);
unassignedPairs.Remove(rootPair);
var membersToVisit = new Queue<string>(rootPair.BothObjects);
var visited = new HashSet<string>();
while (members.Count != 0)
{
string member = membersToVisit.Dequeue();
visited.Add(member);
foreach (var newPair in unassignedPairs
.Where(p => p.BothObjects.Contains(member)).ToList())
{
group.Add(newPair);
unAssignedPairs.Remove(newPair);
foreach (var newMember in newPair.BothObjects.Except(visited))
{
membersToVisit.Enqueue(newMember)
}
}
}
groups.Add(group);
}
return groups;
}
答案 1 :(得分:0)
这只是一个解决方案的想法。
你需要知道你有多少独特的'个人'。对于你的例子,它是26。
首先,你创建了一个26对的字典,其中key是个体,在我们的例子中是一个字母,值是一个组号,它将在最后。对于每对,初始值应为零。
其次,保留一个'groupNumber'整数变量,用于存储下一个组号。你用1初始化它。
然后,您遍历GroupPairs列表。您获取第一个包含“a”和“d”的GroupPair,并将字典中的相应值设置为“1”。
对于每个后续的GroupPair,您将获取其个人并在字典中查找相应的值。
如果其中一个值非零,即其中一个人已经属于某个组,则将另一个值设置为相同的数字,从而将其置于同一组中。
如果两个值均为零,则将它们设置为“groupNumber”并递增“groupNumber”。
如果两个值都不为零,那么它就会变得有点棘手。您可以在组字典中找到所有对,其中value等于该对中的第二个值,并将其值设置为该对中的第一个值。
完成后,再次迭代GroupPairs列表。对于每一对,您在组词典中查找第一个人,从而找出该组所属的组。
希望有道理......
答案 2 :(得分:0)
此代码与示例输入匹配并生成所需的输出。基本上,我为每个组保留一个HashSet项目,并列出要处理的剩余项目。
private static void GroupPairs(List<Tuple<string, string>> pairs)
{
int groupCounter = 0;
while (pairs.Count > 0)
{
var onegroup = new HashSet<string>();
Console.WriteLine("Group {0}", ++groupCounter);
int initialGroupCount;
do
{
var remainder = new List<Tuple<string, string>>();
initialGroupCount = onegroup.Count;
foreach (var curr in pairs)
{
if (onegroup.Contains(curr.Item1) ||
onegroup.Contains((curr.Item2)) ||
onegroup.Count == 0)
{
Console.WriteLine("{0} {1}", curr.Item1, curr.Item2);
onegroup.Add(curr.Item1);
onegroup.Add(curr.Item2);
}
else
{
remainder.Add(curr);
}
}
pairs = remainder;
} while (initialGroupCount < onegroup.Count);
}
}
答案 3 :(得分:0)
为了完整起见,我还有一个递归解决方案。 接近结尾的是GroupPair类,它充当datacontainer,有两个辅助方法:Add和Merge。
你这样调用它:
var gp = GroupByPairs(
new List<Tuple<string, string>>
{
new Tuple<string, string>("a", "d"),
new Tuple<string, string>("f", "h"),
/* you get the idea */
}.GetEnumerator());
foreach (var groupData in gp)
{
Console.WriteLine(groupData.ToString());
}
//recursive take on the problem
private static IEnumerable<GroupPair> GroupByPairs(
IEnumerator<Tuple<string, string>> pairs)
{
// result Groups
var listGroup = new List<GroupPair>();
if (pairs.MoveNext())
{
var item = pairs.Current;
var current = new GroupPair(item);
var subgroup = GroupByPairs(pairs); // recurse
// loop over the groups
GroupPair target = null;
foreach (var groupData in subgroup)
{
// find the group the current item matches
if (groupData.Keys.Contains(item.Item1) ||
groupData.Keys.Contains(item.Item2))
{
// determine if we already have a target
if (target == null)
{
// add item and keep groupData
target = groupData;
groupData.Add(item);
listGroup.Add(groupData);
}
else
{
// merge this with target
// do not keep groupData
target.Merge(groupData);
}
}
else
{
// keep groupData
listGroup.Add(groupData);
}
}
// current item not added
// store its group in the listGroup
if (target == null)
{
listGroup.Add(current);
}
}
return listGroup;
}
public class GroupPair
{
private static int _groupsCount = 0;
private int id;
public GroupPair(Tuple<string, string> item)
{
id = Interlocked.Increment(ref _groupsCount);
Keys = new HashSet<string>();
Items = new List<Tuple<string, string>>();
Add(item);
}
// add the pair and update the Keys
public void Add(Tuple<string, string> item)
{
Keys.Add(item.Item1);
Keys.Add(item.Item2);
Items.Add(item);
}
// Add all items from another GroupPair
public void Merge(GroupPair groupPair)
{
foreach (var item in groupPair.Items)
{
Add(item);
}
}
public HashSet<string> Keys { get; private set; }
public List<Tuple<string, string>> Items { get; private set; }
public override string ToString()
{
var build = new StringBuilder();
build.AppendFormat("Group {0}", id);
build.AppendLine();
foreach (var pair in Items)
{
build.AppendFormat("{0} {1}", pair.Item1, pair.Item2);
build.AppendLine();
}
return build.ToString();
}
}