【问题标题】:Copy all matching items from one list to another将所有匹配项从一个列表复制到另一个列表
【发布时间】:2015-06-07 08:57:09
【问题描述】:

考虑下面的代码

List<string> one = new List<string>();
List<string> two = new List<string>();

列表一包含 3 个字符串

Test 1
Test 1
Test 2

如何匹配字符串 Test 1 并将每个匹配的字符串放入 List two 并从列表一中删除匹配的字符串,这样它就只剩下 Test 2 字符串

这是我目前所拥有的

if (one.Any(str => str.Contains("Test 1")))
{
   //What to do here 
}

如果我使用AddRange(),它会将整个列表一添加到列表二

【问题讨论】:

  • 这是什么意思:我将如何匹配字符串Test 1并将每个匹配的字符串放入列表二; 匹配字符串 Test 1 到底是什么意思
  • 你在找Intersectdotnetperls.com/intersect
  • 我建议您尝试查看 foreach 循环并让它循环列表 1 中的每个项目。如果它在列表 1 中找到某些内容,请将其放入列表 2 并将其从列表 1 中删除。这可以通过使用indexOfremoveAt 来完成。我想你可以自己弄清楚如何使用它们。
  • @SriramSakthivel 我想检查列表一是否包含某个字符串,如果确实如此,则将该特定字符串放入列表二并将其从列表一中删除
  • @Izzy:这不是完全不同的要求吗?所以你想检查one是否包含“Test 1”,如果它确实从one中删除了所有“Test 1”并将一个“Test 1”添加到two,对吗?

标签: c#


【解决方案1】:

这个任务也可以用 Linq 来解决,如下所示。

var NewOne = one.Where(iString => iString == "Test1")
var NewTwo = one.Except(NewOne);

one = NewOne.ToList();
two = NewTwo.ToList();

【讨论】:

  • Except 的一个非常重要的副作用是它不仅会删除“Test1”,还会删除任何重复项。那是因为Except 是一个设置操作。因此,如果原始集合由[Test1, Test2, Test2] 组成,则结果将是[Test2]
  • 他想从one 中删除所有“Test1”并将它们添加到two。所以实际上他想转移他们。
【解决方案2】:

所以您想从one 中删除所有“Test1”并将它们添加到two。那么实际上您想将它们从一个列表转移到另一个列表吗?

string toFind = "Test 1";
var foundStrings = one.Where(s => s == toFind);
if(foundStrings.Any())
{
    two.AddRange(foundStrings);
    one.RemoveAll(s => s == toFind);
}

这是一个更高效但可能不那么可读的非 LINQ 版本:

// backwards loop because you're going to remove items via index
for (int i = one.Count - 1; i >= 0; i--)
{
    string s1 = one[i];
    if (s1 == toFind)
    {
        two.Add(toFind);
        one.RemoveAt(i);
    }
}

【讨论】:

  • 感谢这对我帮助很大
【解决方案3】:

如果你想检查这个字符串:

string match = "Test1";

然后使用这个:

 two.AddRange(one.Where(x => x == match));

将列表one中的所有匹配记录放入列表two

然后,使用这个:

    one.RemoveAll(x => x == match);

从列表one中删除所有匹配的记录。

【讨论】:

    【解决方案4】:

    这个怎么样?

    two.AddRange(one.FindAll(x => x.Contains("Test 1")));
    one.RemoveAll(x => two.Contains(x));
    

    以下代码

    List<string> one = new List<string>();
    List<string> two = new List<string>();
    
    one.Add("Test 1");
    one.Add("Test 1");
    one.Add("Test 2");
    
    two.AddRange(one.FindAll(x => x.Contains("Test 1")));
    one.RemoveAll(x => two.Contains(x));
    
    Console.WriteLine("ONE:");
    foreach (string s in one)
    {
        Console.WriteLine(s);
    }
    Console.WriteLine("TWO:");
    foreach (string s in two)
    {
        Console.WriteLine(s);
    }
    Console.ReadLine();
    

    应该会导致

    ONE:
    Test 2
    TWO:
    Test 1
    Test 1
    

    【讨论】:

      【解决方案5】:

      试试

              List<string> two = (from i in one
                                  where i.Contains("Test 1")
                                  select i).ToList();
      
              one = one.Except(two).ToList();
      

      或者更简洁:

      List<string> two = one.Where(i => i.Contains("Test 1")).ToList();
      one = one.Except(two).ToList();
      

      【讨论】:

        【解决方案6】:

        我会这样做:

        //set string to match
        string match = "Test 1";
        //check each item in the list
        for(int i =0; i<one.Count;i++) 
           {
           if (one[i].Equals(match)) //see if it matches
              {
              int index = one.IndexOf(match);//get index of the matching item
              one.RemoveAt(index);//remove the item
              two.Add(match);//add the item to the other list
              }
          }
        

        【讨论】:

          【解决方案7】:

          试试这个:

          two = one.FindAll(x => x.Contains("Test 1");
          one.RemoveAll(x => x.Contains("Test 1");
          

          【讨论】:

          • 考虑添加一个解释,说明此代码如何比现有答案更好地解决问题。一般来说,有解释的答案得分高于没有解释的答案。
          【解决方案8】:

          Sequences 有一个针对这个特定用例的方法,Sequence&lt;T&gt;.Partition

          var lists = one.AsSequence().Partition(x => x == "Test1");
          
          var withTestOne = lists.Item1;
          var withoutTestOne = lists.Item2;
          

          【讨论】:

            【解决方案9】:

            作为一个非 LINQ 解决方案的示例,这似乎工作得很好:

            List<string> one = new List<string>(new[] {"Test 1", "Test 1", "Test 2"});
            List<string> two = new List<string>();
            var toRemove = new List<string>();
            
            foreach (var value in one)
            {
                if(value.Equals("Test 1"))
                {
                    toRemove.Add(value);
                    two.Add(value);
                }
            }
            
            foreach (var value in toRemove)
            {
                one.Remove(value);
            }
            

            【讨论】:

            • 我完全知道这不是“最巧妙”的答案,但仍然......它无效吗?
            • 我必须和@roryap 一起去。除了命名约定之外,它仍然是获得 OP 所追求的结果的解决方案。
            【解决方案10】:

            另一种选择是使用 groupby 子句。下面,我提供了一个演示。我已经包含了检索特定项目(例如测试 1)的方法以及移动所有现有重复项目的方法。 (更多细节参见代码 cmets。)

            class Program
            {
                static List<string> _firstList;
                static List<string> _secondList;
            
                static void Main(string[] args)
                {
                    // Initialize test values
                    Setup();
            
                    // Display whats presenting in list 1.
                    Display();
            
                    // Fill list 2 with all items in list 1 where the item is a value and remove the item
                    // from list 1.
                    FillListTwoWithSpecificValue("Test 1");
            
                    /* Uncomment the line below if you want to populate list 2 with all duplicate items
                                 while removing them from list 1.*/
                    // FillListWithAllDuplicates();
            
                    // Display the results after changes to list 1 and list 2 have been applied.
                    Display();
            
                    Console.ReadLine();
                }
            
                // Bonus method.  Fills list 2 with any instance of a duplicate item pre-existing in list 1 while removing the item from the list.
                static void FillListTwoWithAllDuplicates()
                {
                    // Group the items in the first list
                    var duplicates = _firstList
                        .GroupBy(item => item)
                        .Where(g => g.Count() > 1)
                        .SelectMany(grp => grp);
            
                    // Iterate through each duplicate in the group of duplicate items and add them to the second list and remove it from the first.
                    foreach (var duplicate in duplicates)
                    {
                        _secondList.Add(duplicate);
            
                        // Remove all instances of the duplicate value from the first list.
                        _firstList.RemoveAll(item => item == duplicate);
                    }
                }
            
                // Fill list 2 with any instance of a value provided as a parameter (eg. Test 1) and remove the same value from list 1.
                static void FillListTwoWithSpecificValue(string value)
                {
                    // Group the items in the first list, and select a group according to the value provided.
                    var duplicates = _firstList
                        .GroupBy(item => item)
                        .SelectMany(grp => grp.Where(item => item == value));
            
                    // Iterate through each duplicate in the group of duplicate items and add them to the second list and remove it from the first.
                    foreach (string duplicate in duplicates)
                    {
                        _secondList.Add(duplicate);
            
                        // Remove all instances of the duplicate value from the first list.
                        _firstList.RemoveAll(item => item == duplicate);
                    }
                }
            
                // Simply a method to initialize the lists with dummy data.  This is only meant to keep the code organized.
                static void Setup()
                {
                    // Initialize lists
                    _firstList = new List<string>()
                    {
                        "Test 1",
                        "Test 1",
                        "Test 2",
                        "Test 3",
                        "Test 3",
                        "Test 4",
                        "Test 4",
                        "Test 5",
                        "Test 6",
                    };
            
                    _secondList = new List<string>();
                }
            
                // Simply a method to display the output to the console for the purpose of demonstration.  This is only meant to keep the code organized.
                static void Display()
                {
                    // Checking to see if the second list has been populated. If not, lets just display what's in list 1
                    // since no changes have been made.
                    if (_secondList.Count == 0)
                    {
                        // Display the list 1 values for comparison.
                        Console.WriteLine("Items contained in list 1 before items moved to list 2:\n------------------------------------");
                        foreach (var item in _firstList)
                        {
                            Console.WriteLine(item);
                        }
                    }
                    else
                    {
                        Console.WriteLine("\nItems now in list 1 after duplicates being removed:\n------------------------------------");
                        foreach (var item in _firstList)
                        {
                            Console.WriteLine(item);
                        }
            
                        Console.WriteLine("\nItems now in list 2:\n------------------------------------");
                        foreach (var item in _secondList)
                        {
                            Console.WriteLine(item);
                        } 
                    }
                }
            }
            

            结果如下:

            Items contained in list 1 before items moved to list 2:
            ------------------------------------
            Test 1
            Test 1
            Test 2
            Test 3
            Test 3
            Test 4
            Test 4
            Test 5
            Test 6
            
            Items now in list 1 after duplicates being removed:
            ------------------------------------
            Test 2
            Test 3
            Test 3
            Test 4
            Test 4
            Test 5
            Test 6
            
            Items now in list 2:
            ------------------------------------
            Test 1
            Test 1
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-07-21
              • 1970-01-01
              • 1970-01-01
              • 2022-11-12
              • 2012-08-12
              • 2010-10-05
              • 2013-04-27
              相关资源
              最近更新 更多