我想编写一个通过IEnumerable的函数。对于IEnumerable中的每个项目,它获取一个枚举属性。如果IEnumerable中的所有内容都具有该属性的相同值,则返回该值。否则,它返回null。我可以做到这一点,但不是优雅的。我可以使用Linq表达式吗?请参阅下面的UniqueOption功能。
namespace Play
{
public enum Option
{
Tom,
Dick,
Harry
}
public class OptionHolder
{
public Option Option { get; set; }
public override string ToString()
{
return Option.ToString();
}
}
public class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Program p1 = new Program(Option.Tom, Option.Dick, Option.Harry);
Console.WriteLine("1: "+p1.UniqueOption()); //should be null
Program p2 = new Program(Option.Dick, Option.Dick, Option.Dick);
Console.WriteLine("2: " + p2.UniqueOption()); //should be Dick
Program p3 = new Program(Option.Harry);
Console.WriteLine("3: " + p3.UniqueOption()); //should be Harry
}
public Program(params Option[] options)
{
optionList = new List<OptionHolder>();
foreach (Option option in options)
{
OptionHolder holder = new OptionHolder();
holder.Option = option;
optionList.Add(holder);
}
}
/**
* If all the OptionHolders in the Holders property have the same Option, return this.
* Otherwise (there are no OptionHolders, or there is more than one but they hold different Options), return null.
*/
public Option? UniqueOption()
{
Option? option = null;
foreach(OptionHolder holder in optionList) {
Option o = holder.Option;
if (option == null)
{
option = o;
}
else if (option != o)
{
return null;
}
}
return option;
}
private List<OptionHolder> optionList;
public IEnumerable<OptionHolder> Holders
{
get { return optionList; }
}
public override string ToString()
{
return String.Join(",", optionList);
}
}
}
答案 0 :(得分:2)
如果我理解正确,那么您可以使用Linq的Distinct
方法。
public Option? UniqueOption()
{
var distinct = optionList.Select(x=> x.Option).Distinct();
if(distinct.Count() == 1)
{
return distinct.First();
}
return null;
}
public Option? UniqueOptionOptimized()
{
HashSet<Option> set = new HashSet<Option>();
foreach (var item in optionList)
{
if (set.Add(item.Option) && set.Count > 1)
{
return null;
}
}
if (set.Count == 1)
return set.First();
else
return null;
}
public Option? UniqueOptionOptimized2()
{
using(var distinctEnumerator = optionList.Select(x => x.Option).Distinct().GetEnumerator())
{
if(distinctEnumerator.MoveNext())
{
var firstOption = distinctEnumerator.Current;
if(!distinctEnumerator.MoveNext())
return firstOption;
}
}
return null;
}
答案 1 :(得分:1)
使用Distinct()
和Take(2)
一旦找到两个不同的选项就停止枚举列表,然后检查是否找到了一个不同的选项(而不是零或两个):
public Option? UniqueOption()
{
Option[] options = optionList.Select(holder => holder.Option).Distinct().Take(2).ToArray();
return options.Length == 1 ? options[0] : (Option?)null;
}
UPDATE:要检查实际枚举的值数,可以使用以下帮助程序方法:
public static IEnumerable<T> Trace<T>(IEnumerable<T> values)
{
foreach (T value in values)
{
Console.WriteLine("Yielding {0}...", value);
yield return value;
}
}
这样称呼:
Option[] options = Trace(optionList).Select(holder => holder.Option).Distinct().Take(2).ToArray();
这表明p1
仅枚举Tom
和Dick
,而不是Harry
。
答案 2 :(得分:0)
以下功能应符合您的需要。但是,我尝试使用更简单的应用程序,但您应该能够按照自己的意愿进行安排。
public Option? UniqueOption(params Option[] args)
{
if (args == null)
return null; //or maybe throws?
var d = args.Distinct().ToArray();
return d.Length != 1
? d[0]
: new Nullable<Option>();
}
答案 3 :(得分:0)
[STAThread]
private static void Main()
{
Option tested = Option.Paul;
Program p4 = new Program(Option.Paul, Option.Paul, Option.Paul);
Console.WriteLine("4: " + p4.UniqueOption(tested));
}
public Option? UniqueOption(Option tested)
{
if (optionList.All(o => o.Option == tested))
return tested;
return null;
}
答案 4 :(得分:0)
另一种变体:
public Option? UniqueOption()
{
if(!optionList.Any()) return null;
var first = optionList.First();
return optionList.All(a => first.Option == a.Option) ? (Option?)first.Option : null;
}
答案 5 :(得分:0)
我最终使用的东西与我原来的解决方案没有什么不同。不过,当我得到更多时间时,我会再看看这个。
public Option? UniqueOption()
{
IEnumerator<OptionHolder> enumerator = Holders.GetEnumerator();
bool hasMoreElements;
Option? result=null;
do
{
hasMoreElements = enumerator.MoveNext();
if (hasMoreElements)
{
Option? option = enumerator.Current.Option;
result = (result != null && result != option) ? null : option;
}
}
while (hasMoreElements && result != null);
return result;
}