【问题标题】:Remove all similar elements in an array if count of element is less than 'n'如果元素的计数小于“n”,则删除数组中的所有相似元素
【发布时间】:2016-04-25 10:47:41
【问题描述】:

我有一个包含数千个元素的数组,其中许多元素是其他元素的副本。我需要的是一种方法来查找数组中'foo'元素的计数,如果小于'n',则从数组中删除'foo'的所有元素。

我需要的示例

string[] words = new string[]
int n = 8;
int k = Occurances of "foo" in words;
if (k < n) {
    //Remove all occurances of 'foo' in the array
}

如果数组 'words' 中的起始元素是

{"foo","foo","foo","foo","foo","foo","foo","bar","bar","bar","bar","bar","bar","bar","bar","bar"}

结果将是数组中的左下角,因为只找到了 7 次出现的“foo”,但发现了 9 次出现的“bar”

{"bar","bar","bar","bar","bar","bar","bar","bar","bar"}

感谢任何帮助

【问题讨论】:

  • @Hendry 我尝试将内容转储到Dictionary,获取字典中每个元素的计数,然后相应地删除,但是来回转换无法正常工作,并且是全身疼痛
  • 元素的原始顺序重要吗?

标签: c# arrays


【解决方案1】:

您可以使用 LINQ GroupByCount 来实现:

string[] words = new string[] { "foo", "foo", "foo", "foo", "foo", "foo", "foo", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar" };
int n = 8;
var groups = words.GroupBy(x => x).Where(g => g.Count() >= n);

您在这里所做的是按元素值(foo 组和 bar 组)对元素进行分组,并对每个组进行计数,得到元素数量大于某个阈值的组(在您的情况下为 n = 8)

要取回数组,您只需使用SelectMany 进一步改进:

string[] filteredWords = words.GroupBy(x => x).Where(g => g.Count() >= n)
    .SelectMany(g => g).ToArray();

【讨论】:

  • 这很好用,但它以IGrouping 的形式留下结果。如何将其转换回数组?
  • 你可以用SelectMany进步一点,我会更新我的答案
  • 完美。这正是我想要的!
  • 现在可以进一步扩展它,并检查部分字符串中的出现吗?例如,我可能有“foo extrabits”和“bar extrabits”,我可以用你的方法只检查字符串的 foo 和 bar 吗?
  • 在这种情况下,您应该进行双重处理。但这取决于您希望checking 的行为方式。例如,“字符串的出现”可能意味着两种不同的东西:(1)“boa”出现在“boasting”中(2)“boa”不在“boasting”中出现,而是出现在“boa snake”中
【解决方案2】:

这很有效,它保留了元素的原始顺序。

var words = new[]
{
    "foo", "foo", "foo", "foo", "foo",
    "foo", "foo", "bar", "bar", "bar",
    "bar", "bar", "bar", "bar", "bar",
    "bar"
};

var keepers = new HashSet<string>(
    words.ToLookup(x => x).Where(x => x.Skip(7).Any()).Select(x => x.Key));

words = words.Where(w => keepers.Contains(w)).ToArray();

如果顺序不重要,那么就可以了:

words =
    words
        .ToLookup(x => x)
        .Where(x => x.Skip(7).Any())
        .SelectMany(x => x)
        .ToArray();

根据您的评论,“是否可以进一步扩展它,并检查字符串的某些部分是否出现?”,我假设您的意思是您要计算“单词”部分的单个频率如果满足频率要求,则保留整个“单词”。这可能不是很清楚。这是我的代码:

var words = new[]
{
    "foo", "foo", "foo extrabits", "foo", "foo",
    "foo", "foo", "bar", "bar", "bar",
    "bar", "bar", "bar extrabits", "bar", "bar",
    "bar"
};

var keepers =
    new HashSet<string>(
        words
            .SelectMany(x => x.Split(' '))
            .ToLookup(x => x)
            .Where(x => x.Skip(7).Any())
            .Select(x => x.Key));

words =
    words
        .Where(x => x.Split(' ').Any(y => keepers.Contains(y)))
        .ToArray();

这会产生:

酒吧 酒吧 酒吧 酒吧 酒吧 酒吧外卖 酒吧 酒吧 酒吧

【讨论】:

  • 是否可以进一步扩展它,并检查部分字符串的出现情况?例如,我可能有“foo extrabits”和“bar extrabits”,我可以用你的方法只检查字符串的 foo 和 bar 吗?
  • @CocoaMix86 - 是的,您可以在.ToLookup(...) 之前使用.Split(' ').SelectMany(...) 轻松做到这一点。
猜你喜欢
  • 1970-01-01
  • 2017-04-27
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 2020-10-21
  • 2020-08-29
  • 2014-11-24
相关资源
最近更新 更多