简体   繁体   中英

comparing two lists and removing missing numbers with C#

there are two lists:

List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });

how do you compare two lists, find missing numbers in List1 and remove these numbers from List1? To be more precise, I need to find a way to specify starting and ending position for comparison.

I imagine that the proccess should be very similar to this:

Step 1.

int start_num = 3; // we know that comparisons starts at number 3
int start = list2.IndexOf(start_num); // we get index of Number (3)
int end = start + 2; // get ending position
int end_num = list2[end]; // get ending number (6)

now we've got positions of numbers (and numbers themselves) for comparison in List2 (3,5,6)

Step 2. To get positions of numbers in List1 for comparison - we can do the following:

int startlist1 = list1.IndexOf(start_num); // starting position
int endlist1 = list1.IndexOf(end_num); // ending position

the range is following: (3,4,5,6)

Step 3. Comparison. Tricky part starts here and I need a help with it

Basically now we need to compare list2 at (3,5,6) with list1 at (3,4,5,6). The missing number is "4".

// I have troubles with this step but the result will be:

int remove_it = 4; // or int []

Step 4. Odd number removal.

int remove_it = 4;
list1 = list1.Where(a => a != remove_it).ToList();

works great, but what will happen if we have 2 missing numbers? ie

int remove_it = 4 // becomes int[] remove_it = {4, 0}

Result As you have guessed the result is new List1, without number 4 in it.

richTextBox1.Text = "" + string.Join(",", list1.ToArray()); // output: 0,1,2,3,5,6

textBox1.Text = "" + start + " " + start_num; // output: 2 3
textBox3.Text = "" + end + " " + end_num; // output: 4 6

textBox2.Text = "" + startlist1; // output: 3
textBox4.Text = "" + endlist1; // output: 6

Can you guy help me out with Step 3 or point me out to the right direction?

Also, can you say what will happen if starting number(start_num) is the last number, but I need to get next two numbers? In example from above numbers were 3,5,6, but they should be no different than 5,6,0 or 6,0,1 or 0,1,2 .

Just answering the first part:

 var list3 = list1.Intersect(list2);

This will set list3 to { 0, 1, 2, 3, 4, 5, 6 } - { 0, 4 } = { 1, 2, 3, 5, 6 }

And a reaction to step 1 :

int start_num = 3; // we know that comparisons starts at number 3
int start = list2.IndexOf(start_num); // we get index of Number (3)
int end = start + 2; // get ending position

From where do you get all those magic numbers (3, + 2 )?

I think you are over-thinking this, a lot.

var result = list1.Intersect(list2)

You can add a .ToList on the end if you really need the result to be a list.

        List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4 
        List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });

        // find items in list 2 notin 1
        var exceptions = list1.Except(list2);

        // or are you really wanting to do a union? (unique numbers in both arrays)
        var uniquenumberlist = list1.Union(list2);

        // or are you wanting to find common numbers in both arrays
        var commonnumberslist = list1.Intersect(list2);

maybe you should work with OrderedList instead of List...

Something like this:

list1.RemoveAll(l=> !list2.Contains(l));

You can use Intersect in conjunction with Skip and Take to get the intersection logic combined with a range (here we ignore the fact 0 is missing as we skip it):

static void Main(string[] args)
{
    var list1 = new List<int> { 1, 2, 3, 4, 5 };
    var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };

    foreach (var i in list2.Skip(3).Take(3).Intersect(list1))
        Console.WriteLine(i); // Outputs 3 then 5.

    Console.Read();
}

Though if I'm being really honest, I'm not sure what is being asked - the only thing I'm certain on is the intersect part:

var list1 = new List<int> { 1, 2, 3, 4, 5 };
var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };

foreach (var i in list2.Intersect(list1))
    Console.WriteLine(i); // Outputs 1, 2, 3, 5.

To get the numbers that exist in list1 but not in list2 , you use the Except extension method:

IEnumerable<int> missing = list1.Except(list2);

To loop through this result to remove them from list1 , you have to realise the result, otherwise it will read from the list while you are changing it, and you get an exception:

List<int> missing = list1.Except(list2).ToList();

Now you can just remove them:

foreach (int number in missing) {
  list1.Remove(number);
}

I'm not sure I understand your issue, and I hope the solution I give you to be good for you.

You have 2 lists:

List list2 = new List(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4 List list1 = new List(new[] { 0, 1, 2, 3, 4, 5, 6 });

To remove from list1 all the missing numbers in list2 I suggest this solution: Build a new list with missing numbers:

List diff = new List();

then put all the numbers you need to remove in this list. Now the remove process should be simple, just take all the elements you added in diff and remove from list2.

Did I understand correctly that algorithm is: 1) take first number in List 2 and find such number in List1, 2) then remove everything from list 1 until you find second number form list2 (5) 3) repeat step 2) for next number in list2.?

ok, seems like I hadn't explained the problem well enough, sorry about it. Anyone interested can understand what I meant by looking at this code:

        List<int> list2 = new List<int>() { 1, 2, 3, 5, 6 }; // missing: 0 and 4
        List<int> list1 = new List<int>() { 0, 1, 2, 3, 4, 5, 6 };

        int number = 3; // starting position

        int indexer = list2.BinarySearch(number);
        if (indexer < 0)
        {
            list2.Insert(~index, number); // don't look at this part
        }

        // get indexes of "starting position"
        int index1 = list1.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;
        int index2 = list2.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;

        // reorder lists starting at "starting position"
        List<int> reorderedList1 = list1.Skip(index1).Concat(list1.Take(index1)).ToList(); //main big
        List<int> reorderedList2 = list2.Skip(index2).Concat(list2.Take(index2)).ToList(); // main small


        int end = 2; // get ending position: 2 numbers to the right
        int end_num = reorderedList2[end]; // get ending number

        int endlist1 = reorderedList1.IndexOf(end_num); // ending position

        //get lists for comparison
        reorderedList2 = reorderedList2.Take(end + 1).ToList();
        reorderedList1 = reorderedList1.Take(endlist1 + 1).ToList();

        //compare lists
        var list3 = reorderedList1.Except(reorderedList2).ToList();
        if (list3.Count != 0)
        {
            foreach (int item in list3)
            {
                list1 = list1.Where(x => x != item).ToList(); // remove from list
            }
        }
        // list1 is the result that I wanted to see

if there are any ways to optimize this code please inform me. cheers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM