1

Consider the following code

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

List one contains 3 strings

Test 1
Test 1
Test 2

How would I match the string Test 1 and put each matching string in List two and remove the matching strings from list one so it's left with only Test 2 string

This is what I have so far

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

If I use AddRange() it adds the entire list one to list two

Izzy
  • 6,740
  • 7
  • 40
  • 84
  • 5
    What do you mean by this: *How would I match the string Test 1 and put each matching string in List two*; What exactly you mean by *match the string Test 1* – Sriram Sakthivel Apr 02 '15 at 11:58
  • Are you looking for `Intersect` http://www.dotnetperls.com/intersect – Kaushik Apr 02 '15 at 12:00
  • I suggest you try to look into the `foreach` loop and have it loop each item in list 1. if it finds something in list 1,place it in list 2 and remove it form list 1. that could be done by using `indexOf` and `removeAt`. I think you can figure out how to use them by your self. – maam27 Apr 02 '15 at 12:00
  • @SriramSakthivel I want to check if list one contains a certian string and if it does then place that particular string to list two and remove it from list one – Izzy Apr 02 '15 at 12:02
  • @Izzy: isn't that a completely different requirement? So you want to check if `one` contains "Test 1", if it does remove all "Test 1" from `one` and add a single "Test 1" to `two`, is that correct? – Tim Schmelter Apr 02 '15 at 12:28
  • @TimSchmelter sorry if it came across wrong but I want to add each "Test 1" string to List 2 – Izzy Apr 02 '15 at 12:30

10 Answers10

4

The task could also be solved with Linq as follows.

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

one = NewOne.ToList();
two = NewTwo.ToList();
Codor
  • 17,447
  • 9
  • 29
  • 56
  • 1
    One very important side effect of `Except` is that it not only removes "Test1", but also any duplicates. That's because `Except` is a *set operation*. So if the original collection was composed of `[Test1, Test2, Test2]`, the result would be `[Test2]` – dcastro Apr 02 '15 at 12:24
  • 1
    He wants to remove all "Test1" from `one` and add them to `two`. So actually he wants to transfer them. – Tim Schmelter Apr 02 '15 at 12:39
1

If you want to check against this string:

string match = "Test1";

then use this:

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

to place all matching records from list one into list two.

Then, use this:

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

to remove all matching records from list one.

Giorgos Betsos
  • 71,379
  • 9
  • 63
  • 98
1

how about this?

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

The following code

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();

should result in

ONE:
Test 2
TWO:
Test 1
Test 1
sebingel
  • 470
  • 4
  • 17
1

So you want to remove all "Test1" from one and add them to two. So actually you wants to transfer them from one list to another?

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

Here's a non-LINQ version that is more efficient but perhaps not as readable:

// 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);
    }
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

As an example of a non-LINQ solution, seems like this works well enough:

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);
}
rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • I'm fully aware this isn't the "slickest" answer, but still...is it not valid? – rory.ap Apr 02 '15 at 12:19
  • 1
    I have to go with @roryap on this one. Other than naming convention, it's still a solution to getting the result that the OP is after. – James Shaw Apr 02 '15 at 12:42
0

Try

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

        one = one.Except(two).ToList();

Or more concise :

List<string> two = one.Where(i => i.Contains("Test 1")).ToList();
one = one.Except(two).ToList();
Rom Eh
  • 1,981
  • 1
  • 16
  • 33
0

I would do something like this:

//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
      }
  }
maam27
  • 444
  • 3
  • 21
0

Try this:

two = one.FindAll(x => x.Contains("Test 1");
one.RemoveAll(x => x.Contains("Test 1");
anon
  • 192
  • 6
  • 1
    Consider adding an explanation of how this code would solve the problem better than the existing answers. Generally, answers with explanations score higher than those without. – Heretic Monkey Apr 02 '15 at 12:57
0

Sequences has a method for this specific use case, Sequence<T>.Partition.

var lists = one.AsSequence().Partition(x => x == "Test1");

var withTestOne = lists.Item1;
var withoutTestOne = lists.Item2;
dcastro
  • 66,540
  • 21
  • 145
  • 155
0

Another option would be to use a groupby clause. Below, I've provided a demonstration. I've included both a method to retrieve a specific item (eg. Test 1) as well as a method to move all existing duplicate items. (See the code comments for further detail.)

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);
            } 
        }
    }
}

The results would be the following:

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
James Shaw
  • 839
  • 1
  • 6
  • 16