Lio Programista
Lio Programista

Reputation: 163

Iteration in two list

I asked this question a week ago and now I found something that I missed.I didnt know if I will get any replies if I reopen the question that's why i created a new one. The last condition doesn't work. I am trying to iterate in two list with different objects.I am adding the records to a third list if they complete the following conditions when I compare listTest1 and listTest2

I know that it sounds quite confusing that is why I will show you what I am getting and what I am expecting.

I am getting, The test 6 object is missing enter image description here

class Program
{
    static void Main(string[] args)
    {
        Test1 test1 = new Test1() { abbrv = "Test1", date = new DateTime(2017, 11, 12), completed = false };
        Test1 test2 = new Test1() { abbrv = "Test2", date = new DateTime(2017, 12, 17), completed = false };
        Test1 test5 = new Test1() { abbrv = "Test5", date = new DateTime(2017, 12, 12), completed = false };

        Test2 test3 = new Test2() { abbrv = "Test1", date = new DateTime(2017, 11, 12), completed = false, abbrevName = "AbbrvName1" };
        Test2 test4 = new Test2() { abbrv = "Test2", date = new DateTime(2017, 12, 12), completed = false, abbrevName = "AbbrvName2" };
        Test2 test7 = new Test2() { abbrv = "Test5", date = new DateTime(2017, 12, 18), completed = false, abbrevName = "AbbrvName3" };
        Test2 test6 = new Test2() { abbrv = "Test6", date = new DateTime(2017, 12, 18), completed = false, abbrevName = "AbbrvName3" };
        List<Test1> listTest1 = new List<Test1>();
        List<Test2> listTest2 = new List<Test2>();
        List<Test2> listTest3 = new List<Test2>();
        listTest1.Add(test1);
        listTest1.Add(test2);
        listTest1.Add(test5);
        listTest2.Add(test6);
        listTest2.Add(test3);
        listTest2.Add(test4);
        listTest2.Add(test7);
        for (int i = 0; i < listTest1.Count; i++)
        {
            bool abbrvFound = false;
            for (int a = 0; a < listTest2.Count; a++)
            {
                if (listTest1[i].abbrv != listTest2[a].abbrv)
                {
                    continue;
                }

                abbrvFound = true;
                if (listTest1[i].date == listTest2[a].date)
                {
                    listTest3.Add(listTest2[a]);
                }
                else
                {
                    listTest3.Add(new Test2() { abbrv = listTest2[a].abbrv, date = listTest2[a].date, completed = true, abbrevName = listTest2[a].abbrevName });
                    listTest3.Add(new Test2() { abbrv = listTest1[i].abbrv, date = listTest1[i].date, completed = listTest1[i].completed, abbrevName = string.Empty });
                }
            }
            if (!abbrvFound)
            {
                listTest3.Add(new Test2() { abbrv = listTest1[i].abbrv, date = listTest1[i].date, completed = listTest1[i].completed, abbrevName = string.Empty });
            }
        }
        foreach (var test in listTest3)
        {
            Console.WriteLine(test.abbrv + " " + test.date + " " + test.completed + " " + test.abbrevName);
        }
        Console.Write(1);
    }
}

public class Test1
{
    public string abbrv { get; set; }
    public DateTime date { get; set; }
    public bool completed { get; set; }
}
public class Test2
{
    public string abbrv { get; set; }
    public DateTime date { get; set; }
    public bool completed { get; set; }
    public string abbrevName { get; set; }
}

Upvotes: 0

Views: 137

Answers (3)

spottedmahn
spottedmahn

Reputation: 15981

I would recommend using MoreLINQ's FullJoin method.

public static List<Data> GetResults(List<Data> list1, List<Data> list2)
{
    var joined = list1.FullJoin(list2, key1 => key1.Abbrv,
        firstSelector => new Data
        {
            Abbrv = firstSelector.Abbrv,
            Date = firstSelector.Date,
            Desc = firstSelector.Desc
        },
        secondSelector => new Data
        {
            Abbrv = secondSelector.Abbrv,
            Date = secondSelector.Date,
            Desc = secondSelector.Desc
        },
        (first, second) => new Data
        {
            Abbrv = second.Abbrv,
            Date = second.Date,
            Desc = second.Desc
        });

    var mem = joined.ToList();

    return mem;
}

UnitTest

[TestMethod]
public void FullTest()
{
    //arrange
    var listTest1 = GetTest1Data();
    var listTest2 = GetTest2Data();

    //act
    var res = Class1.GetResults(listTest1, listTest2);

    //assert
    //If the abbrv and the date is the same I am adding the object from listTest2 to listTest3
    //If the abbrv is the same but the date is different I am adding the object from listTest2 to listTest3 and I am switching the completed property to true.In addition, I am adding the record from listTest1 to listTest3.
    //If the abbrv from listTest1 doesn't exist in listTest2 I am adding the record from listTest1 to listTest3.
    //If the abbrv from listTest2 doesnt exist in listTest2.I am adding the record from listTest2 to listTest2
    var expected = new List<Data> { new Data { Abbrv = "InBothSameDate", Date = new DateTime(2017, 11, 12), Desc = "From2" },
        new Data{ Abbrv="InBothDifferentDate", Date = new DateTime(2017, 12, 12), Desc = "From2" },
        new Data{ Abbrv="OnlyIn1", Date = new DateTime(2017, 1, 1), Desc = "From1"  },
        new Data{ Abbrv="OnlyIn2", Date = new DateTime(2017, 1, 31), Desc = "From2"  }
    };

    //https://stackoverflow.com/questions/11055632/how-to-compare-lists-in-unit-testing
    CollectionAssert.AreEqual(res, expected);
}

Full Source Code

Upvotes: 0

Jonathan Applebaum
Jonathan Applebaum

Reputation: 5986

I would separate the part that checks existence, using LINQ in order to find objects that exist in one list and not in the other list.
then use your algorithm for the rest of the conditions

here is an example that shows how to find objects that are not shared by 2 lists by abbrv name:

var result = listTest1.Where(l => !listTest2.Any(l2 => l2.abbrv == l.abbrv));
var result2 = listTest2.Where(l => !listTest1.Any(l1 => l1.abbrv == l.abbrv));

Console.WriteLine("objects that exist in list 1 and not list list 2, based on abbrv string");
foreach (var t in result)
{
    Console.WriteLine(t.abbrv);
}
Console.WriteLine("objects that exist in list 2 and not list list 1, based on abbrv string");
foreach (var t in result2)
{
    Console.WriteLine(t.abbrv);
}

the output for executing this will be:

objects that exist in list 1 and not list list 2, based on abbrv string
objects that exist in list 2 and not list list 1, based on abbrv string
Test6

Upvotes: 0

Seymour
Seymour

Reputation: 7067

I'm not sure I fully followed your stated conditions, but you seem to be joining two disparate lists. To that end, you may find the following LINQ full outer join helpful.

var leftJoin = from t1 in listTest1
    join t2 in listTest2 on t1.abbrv equals t2.abbrv into lj
    from s in lj.DefaultIfEmpty()
    select new Test2() {abbrv = t1.abbrv, date = t1.date, completed = t1.completed, abbrevName = s.abbrv};

var rightJoin = from t2 in listTest2
    join t1 in listTest1 on t2.abbrv equals t1.abbrv into rj
    from s in rj.DefaultIfEmpty()
    select t2;

var fullOuterJoin = leftJoin.Union(rightJoin);

Upvotes: 2

Related Questions