I am trying to complete an algorithm that adds ProcTime to a max of two other max values (JobNumMax and WSMax). I am having trouble using the FindLastIndex and FindLast in my loops.
Here is my code.
public class JobListOrder
{
public int JobNum { get; set; }
public string Workstation { get; set; }
public int Sequence { get; set; }
public int ProcTime { get; set; }
public int EndHour { get; set; }
public DateTime DueDate { get; set; }
public int Priority { get; set; }
}
Putting into list.
//New List
List<JobListOrder> list = new List<JobListOrder>();
using (StreamReader sr = new StreamReader("C:\\Users\\Nathan\\Documents\\Visual Studio 2013\\Projects\\PubsExample\\PubsExample\\JobsList.txt"))
{
//Add .txt to List
while (sr.Peek() >= 0)
{
string str;
string [] strArray;
str = sr.ReadLine();
strArray = str.Split(',');
JobListOrder currentjob = new JobListOrder();
currentjob.JobNum = int.Parse(strArray[0]);
currentjob.Workstation = strArray[1];
currentjob.Sequence = int.Parse(strArray[2]);
currentjob.ProcTime = int.Parse(strArray[3]);
currentjob.EndHour = int.Parse(strArray[4]);
currentjob.DueDate = DateTime.Parse(strArray[5]);
currentjob.Priority = int.Parse(strArray[6]);
list.Add(currentjob);
}
Sort into a particular way to start calculations
//Job Sort
var ListSort = from jobsort in list
orderby jobsort.Sequence ascending, jobsort.Priority descending, jobsort.DueDate ascending, jobsort.JobNum ascending
select jobsort;
List<JobListOrder> SortList = new List<JobListOrder>(ListSort);
Here is a slight attempt at it
//foreach (var i in SortList)
//{
// if (JobNumMax >= WSMax)
// {
// return i.EndHour = JobNumMax + i.ProcTime;
// }
// else
// return i.EndHour = WSMax + currentjob.ProcTime;
// for (var j = 0; j < SortList.Count; j++)
// {
// int JobLNumMaxIndex = SortList.FindLastIndex(i.JobNum)
// int JobNumMax = i.EndHour[JobNumMaxIndex];
// for (var k = 0; k < SortList.Count; k++)
// {
// int WSMaxIndex = SortList.FindLastIndex(i.Workstation);
// int WSMax = i.EndHour[JobNumMaxIndex];
// }
// }
//}
I am trying to find the LastIndex of a query and return a value of that particular index. I'll try to explain what I mean in the code below Searching for JobNum = 1 and Workstation = Milling with a ProcTime of 1
foreach (var i in SortList) //Iterate through SortList
{
if (JobNumMax (3) >= WSMax (4))
{
return i.EndHour = JobNumMax (3) + i.ProcTime (1); //assigns calculation to EndHour of current record
}
else
return i.EndHour = WSMax (4) + i.ProcTime (1);
for (var j = 0; j < SortList.Count; j++)
{
int JobLNumMaxIndex = SortList.FindLastIndex(1) //Finds last record with JobNum = 1
int JobNumMax = i.EndHour[JobNumMaxIndex];//Return what EndHour is at the index from JobNumMaxIndex search// Lets say 3
for (var k = 0; k < SortList.Count; k++)
{
int WSMaxIndex = SortList.FindLastIndex(Milling);//Finds last record with Workstation = Milling
int WSMax = i.EndHour[JobNumMaxIndex];//Return what EndHour is at the index from WSMaxIndex search// Lets say 4
}
}
}
Result would be 4 + 1 = 5.
I am having trouble with syntax of the algorithm. I can't get the FindLast to work at all.
It looks like you might just be having trouble with the LINQ syntax.
FindLastIndex will take a Predicate<JobListOrder> as an argument, i.e, a function which takes a JobListOrder as an input an returns true or false.
So instead of SortList.FindLastIndex(i.JobNum) you should probably have something like:
SortList.FindLastIndex(order => order.JobNum == i.JobNum);
Corrected in your code:
int JobNumMax = 0;
int WSMax 0;
foreach (var i in SortList)
{
if (JobNumMax >= WSMax)
{
return i.EndHour = JobNumMax + i.ProcTime;
}
else if (JobNumMax > 0 && WSMax > 0)
{
return i.EndHour = WSMax + currentjob.ProcTime;
}
for (var j = 0; j < SortList.Count; j++)
{
int JobLNumMaxIndex = SortList.FindLastIndex(order => order.JobNum == i.JobNum);
JobNumMax = i.EndHour[JobNumMaxIndex];
for (var k = 0; k < SortList.Count; k++)
{
int WSMaxIndex = SortList.FindLastIndex(order => order.Workstation == i.Workstation);
WSMax = i.EndHour[JobNumMaxIndex];
}
}
}
Related
I'm solving Kattis' bokforing problem and one of the test cases fails due to execution time being too long (> 2 sec). Can anyone give me any advice on how I can improve?
class Program
{
static void Main(string[] args)
{
/* Inputs
3 5
SET 1 7
PRINT 1
PRINT 2
RESTART 33
PRINT 1
*/
string first = Console.ReadLine();
int N = Convert.ToInt32(first.Split(" ")[0]);
int Q = Convert.ToInt32(first.Split(" ")[1]);
int[] Accounts = new int[N];
string[] Operations = new string[Q];
for (int i = 0; i < Operations.Length; i++)
{
Operations[i] = Console.ReadLine();
}
for (int i = 0; i < Operations.Length; i++)
{
string[] op = Operations[i].Split(" ");
string operation = op[0];
int accountId = 0;
int ammont = 0;
if (operation == "SET")
{
accountId = Convert.ToInt32(op[1]);
ammont = Convert.ToInt16(op[2]);
Accounts[accountId - 1] = ammont;
}
if (operation == "PRINT")
{
accountId = Convert.ToInt32(op[1]);
Console.WriteLine(Accounts[accountId - 1]);
}
if (operation == "RESTART")
{
ammont = Convert.ToInt16(op[1]);
for (int j = 0; j <= N - 1; j++)
{
Accounts[j] = ammont;
}
}
}
}
}
First of all I copied recommended IO classes from FAQ to the solution, removed double loop (there is no need to loop twice - reading inputs first and then processing them) and then the main trick was to use Dictionary instead of array so there is no need to manually clear it/set amount to all items in it every time:
var scanner = new Scanner();
using(var writer = new BufferedStdoutWriter())
{
var N = scanner.NextInt();
var Q = scanner.NextInt();
var amount = 0;
var Accounts = new Dictionary<int, int>();
for (var i = 0; i < Q; i++)
{
var s = scanner.Next();
var accountId = 0;
if (s == "SET")
{
accountId = scanner.NextInt();
Accounts[accountId] = scanner.NextInt();
}
else if (s == "PRINT")
{
accountId = scanner.NextInt();
if (!Accounts.TryGetValue(accountId, out var value))
{
value = amount;
}
writer.WriteLine(value);
}
else if (s == "RESTART")
{
amount = scanner.NextInt();
Accounts = new Dictionary<int, int>();
}
}
}
I have these objects with a range and list of properties. My goal is to take a list of these objects and create a new list where no ranges overlap. When two ranges are overlapping the overlapping region can be replaced with an object with the union of the properties. I'm hoping a picture can explain this a little better than words can.
Untangling Of Ranges
I was able to achieve this with the following code however it is rather clunky and uses a goto which I try to avoid. The methodology behind this code is to compare every pair of ranges and if there is an intersection, replace both RangeObjects with up to three RangeObjects:
One for the part of rangeObject1 that doesn't intersect rangeObject2
One for the part of rangeObject2 that doesn't intersect rangeObject1
One for the intersection of rangeObject1 and rangeObject2 with unioned properties.
class RangeObject
{
RangeObject(int start, int end, List<object> properties)
{
Start = start;
End = end;
Properties = properties;
}
public int Start { get; set; }
public int End { get; set; }
public int Length { get => End - Start; }
public List<object> Properties { get; }
public bool IsInRange(int value)
{
return value > Start && value < End;
}
private List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
List<RangeObject> list1 = new List<RangeObject>(list);
list1.Sort();
int start = 0;
startover:
for (int i = start; i < list1.Count; i++)
{
for (int j = i + 1; j < list1.Count; j++)
{
if (list1[i].Start < list1[j].End && list1[j].Start < list1[i].End)
{
list1.AddRange(UntangleRanges(list1[i], list1[j]));
list1.Remove(list1[j]);
list1.Remove(list1[i]);
goto startover;
}
}
start++;
}
list1.Sort();
return list1;
}
public List<RangeObject> UntangleRanges(RangeObject rangeObject1, RangeObject rangeObject2)
{
List<RangeObject> result = new List<RangeObject>();
//This is to reduce the number of if cases by allowing the asumption that rangeObject1 is first
if (rangeObject1.Start > rangeObject2.Start || ((rangeObject1.Start == rangeObject2.Start) && (rangeObject1.Length > rangeObject2.Length)))
{
RangeObject temp = rangeObject1;
rangeObject1 = rangeObject2;
rangeObject2 = temp;
}
if (rangeObject1.Start == rangeObject2.Start && rangeObject1.End == rangeObject2.End) //Ranges Equal
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject1.End, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));//Return a RangeObject of Unioned Properties
}
else if(rangeObject1.IsInRange(rangeObject2.Start) && rangeObject1.IsInRange(rangeObject2.End))//Range2 contained in Range1
{
if (rangeObject1.Start != rangeObject2.Start)
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject2.Start - rangeObject1.Start, rangeObject1.Properties));
}
result.Add(new RangeObject(rangeObject2.Start, rangeObject2.Length, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));
if (rangeObject1.End != rangeObject2.End)
{
result.Add(new RangeObject(rangeObject2.End, rangeObject1.End - rangeObject2.End, rangeObject1.Properties));
}
}
else if (rangeObject1.IsInRange(rangeObject2.Start))//Range2.Start contained in Range1
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject2.Start - rangeObject1.Start, rangeObject1.Properties));
result.Add(new RangeObject(rangeObject2.Start, rangeObject1.End - rangeObject2.Start, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));
result.Add(new RangeObject(rangeObject1.End, rangeObject2.End - rangeObject1.End, rangeObject2.Properties));
}
else //No intersection, shouldn't happen
{
result.Add(rangeObject1);
result.Add(rangeObject2);
}
return result;
}
}
Any ideas on how to achieve this a little more elegantly? Or at least avoid the startover because when I cut up the ranges I end up relocating them to the end and changing the length/order of the list so it's hard to tell what ranges I've compared.
For the sake of simplicity I first get a big enough range to include all other ranges, but with an empty Properties field. This is achieved by getting the minimum and maximum value of all ranges.
Then I combine the ranges one after the other with a so-called untangled range list which at the beginning consists of only initialRange. During this process, untangledRanges remains sorted and without any overlapping ranges. So in the end, all the ranges are combined into a list of untangled ranges.
Based on your current code, this is all you need:
class RangeObject
{
public RangeObject(int start, int end, List<object> properties)
{
if (start >= end)
throw new Exception("'start' must be less than 'end'");
Start = start;
End = end;
Properties = properties;
}
public int Start { get; set; }
public int End { get; set; }
public int Length { get => End - Start; }
public List<object> Properties { get; set; }
public List<RangeObject> SplitAt(int point)
{
if (point <= this.Start || point >= this.End)
return new List<RangeObject> { this };
var result = new List<RangeObject>();
result.Add(new RangeObject(this.Start, point, this.Properties));
result.Add(new RangeObject(point, this.End, this.Properties));
return result;
}
public static List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
var initialRange = GetInitialRange(list);
var untangledRanges = new List<RangeObject> { initialRange };
foreach (var rangeObject in list)
{
ExpandUntangleRanges(untangledRanges, rangeObject);
}
return untangledRanges;
}
private static void ExpandUntangleRanges(
List<RangeObject> alreadyUntangledRanges, RangeObject newRange)
{
int firstRangeIndex = alreadyUntangledRanges
.FindIndex(x => x.Start <= newRange.Start && newRange.Start < x.End);
int lastRangeIndex = alreadyUntangledRanges
.FindIndex(x => x.Start < newRange.End && newRange.End <= x.End);
var firstRange = alreadyUntangledRanges[firstRangeIndex];
if (firstRange.Start < newRange.Start)
{
// split the first range
alreadyUntangledRanges.RemoveAt(firstRangeIndex);
alreadyUntangledRanges.InsertRange(
firstRangeIndex, firstRange.SplitAt(newRange.Start));
firstRangeIndex++;
lastRangeIndex++;
}
var lastRange = alreadyUntangledRanges[lastRangeIndex];
if (newRange.End < lastRange.End)
{
// split the last range
alreadyUntangledRanges.RemoveAt(lastRangeIndex);
alreadyUntangledRanges.InsertRange(
lastRangeIndex, lastRange.SplitAt(newRange.End));
}
for (int i = firstRangeIndex; i <= lastRangeIndex; i++)
{
alreadyUntangledRanges[i].Properties = alreadyUntangledRanges[i]
.Properties.Union(newRange.Properties).ToList();
}
}
private static RangeObject GetInitialRange(List<RangeObject> rangeObjects)
{
int? start = null;
int? end = null;
foreach (var rangeObject in rangeObjects)
{
if (start == null || rangeObject.Start < start)
start = rangeObject.Start;
if (end == null || rangeObject.End > end)
end = rangeObject.End;
}
if (start == null || end == null)
return null;
return new RangeObject(start.Value, end.Value, new List<object>());
}
}
The following is one way to get rid of goto:
private List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
List<RangeObject> list1 = new List<RangeObject>(list);
list1.Sort();
int start = 0;
while (!CheckSomething(list1, ref start)) ;
list1.Sort();
return list1;
}
private bool CheckSomething(List<RangeObject> list1, ref int start)
{
for (int i = start; i < list1.Count; i++)
{
for (int j = i + 1; j < list1.Count; j++)
{
if (list1[i].Start < list1[j].End && list1[j].Start < list1[i].End)
{
list1.AddRange(UntangleRanges(list1[i], list1[j]));
list1.Remove(list1[j]);
list1.Remove(list1[i]);
return false;
}
}
start++;
}
return true;
}
Please, help me to eliminate repeating code in "SortMG" and "SortByName" methods. It is basically the same text and it annoys me.
class Student
{
public string name;
public string major;
public double grade;
public string studyForm;
public Student(string name, string major, double grade, string studyForm)
{
this.name = name;
this.major = major;
this.grade = grade;
this.studyForm = studyForm;
}
}
class Program
{
static void SortMG(Student[] sortMG, int n)
{
int i, j;
Student tmpMG = new Student("","", 0, "");
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortMG[j].major.CompareTo(sortMG[i].major)<0)
{
//I'm asking about this part:
tmpMG.name = sortMG[j].name;
tmpMG.major = sortMG[j].major;
tmpMG.studyForm = sortMG[j].studyForm;
tmpMG.grade = sortMG[j].grade;
sortMG[j].name = sortMG[i].name;
sortMG[j].major = sortMG[i].major;
sortMG[j].studyForm = sortMG[i].studyForm;
sortMG[j].grade = sortMG[i].grade;
sortMG[i].name = tmpMG.name;
sortMG[i].major = tmpMG.major;
sortMG[i].studyForm = tmpMG.studyForm;
sortMG[i].grade = tmpMG.grade;
}
else if (sortMG[j].major.CompareTo(sortMG[i].major) == 0)
{
if (sortMG[j].grade > sortMG[i].grade)
{
//and this part:
tmpMG.name = sortMG[j].name;
tmpMG.major = sortMG[j].major;
tmpMG.studyForm = sortMG[j].studyForm;
tmpMG.grade = sortMG[j].grade;
sortMG[j].name = sortMG[i].name;
sortMG[j].major = sortMG[i].major;
sortMG[j].studyForm = sortMG[i].studyForm;
sortMG[j].grade = sortMG[i].grade;
sortMG[i].name = tmpMG.name;
sortMG[i].major = tmpMG.major;
sortMG[i].studyForm = tmpMG.studyForm;
sortMG[i].grade = tmpMG.grade;
}
}
}
}
}
static void SortByName(Student[] sortN, int n)
{
int i, j;
Student tmpN = new Student("", "", 0, "");
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortN[j].name.CompareTo(sortN[i].name) < 0)
{
//and this part:
tmpN.name = sortN[j].name;
tmpN.major = sortN[j].major;
tmpN.studyForm = sortN[j].studyForm;
tmpN.grade = sortN[j].grade;
sortN[j].name = sortN[i].name;
sortN[j].major = sortN[i].major;
sortN[j].studyForm = sortN[i].studyForm;
sortN[j].grade = sortN[i].grade;
sortN[i].name = tmpN.name;
sortN[i].major = tmpN.major;
sortN[i].studyForm = tmpN.studyForm;
sortN[i].grade = tmpN.grade;
}
}
}
}
}
It looks like you are "swapping" items by swapping their property values. Seems like you should be just swapping the items instead:
if (sortMG[j].grade > sortMG[i].grade)
{
//and this part:
tmpMG = sortMG[j];
sortMG[j] = sortMG[i];
sortMG[i] = tmpMG;
}
You could also move that swap into a function that you call from the three locations to reduce duplicate code further:
public void Swap(Student[] sortMG, int i, int j)
{
//TODO: add bounds/null hecking
var tmpMG = sortMG[j];
sortMG[j] = sortMG[i];
sortMG[i] = tmpMG;
}
You could save yourself a lot of work by using Linq.
For example you could sort a Student[] by Major with the following:
List<Student> students = new List<Student>()
{
new Student("Jose Mendez", "Math", 80, "Beta"),
new Student("Alex Bello", "Math", 90, "Alpha"),
new Student("Bob Junior", "EE", 100, "Charlie")
};
Student[] array = students.ToArray();
array = array.OrderBy(x => x.Major).ToArray();
It seems like you are asking for something like:
static void copyStudent(Student from, Student to)
{
Student tmpMG = new Student();
tmpMG.name = from.name;
tmpMG.major = from.major;
tmpMG.studyForm = from.studyForm;
tmpMG.grade = from.grade;
from.name = to.name;
from.major = to.major;
from.studyForm = to.studyForm;
from.grade = to.grade;
to.name = tmpMG.name;
to.major = tmpMG.major;
to.studyForm = tmpMG.studyForm;
to.grade = tmpMG.grade;
}
static void SortMG(Student[] sortMG, int n)
{
int i, j;
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortMG[j].major.CompareTo(sortMG[i].major)<0)
copyStudent(sortMG[j], sortMG[i]);
else if (sortMG[j].major.CompareTo(sortMG[i].major) == 0)
{
if (sortMG[j].grade > sortMG[i].grade)
copyStudent(sortMG[j], sortMG[i]);
}
}
}
}
static void SortByName(Student[] sortN, int n)
{
for (int i = 0; i < n - 1; i++)
for (int j = i; j < n; j++)
if (sortN[j].name.CompareTo(sortN[i].name) < 0)
copyStudent(sortN[j], sortN[i]);
}
why not use:
static void SortMG(Student[] sortMG, int n)
{
sortMG = sortMG.OrderBy(i => i.major).ThenBy(i=> i.grade).ToArray();
}
static void SortByName(Student[] sortN, int n)
{
sortN = sortN.OrderBy(i => i.name).ToArray();
}
I have the following code which does the job of returning a list of records totalling the stock at each location. I am trying to clean up the program before I take it any further. Is there a way to do the same thing with LINQ? I know this is a mess, and I would like to refine it.
Thanks for looking!
private static List < Stock_Paper_Record > Get_Final_List(List < Stock_Paper_Record > Finallist, List < Stock_Paper_Record > papr, List < string > Codes, List < string > locs) {
int ii = 0;
int totalg = 0;
int totall = 0;
int totalp = 0;
decimal gsm = 0;
decimal size1 = 0;
decimal size2 = 0;
int commited = 0;
int OnOrder = 0;
int THRESH = 0;
int iount = 0;
papr.Sort((x, y) => String.Compare(x.Code, y.Code));
Finallist.Sort((x, y) => String.Compare(x.Code, y.Code));
int ic = 0;
int it = 0;
List < string > ls = new List < string > ();
List < decimal > st = new List < decimal > ();
foreach(string s in Codes) {
for (int iii = 0; iii < papr.Count; iii++) {
if (s == papr[iii].Code && papr[iii].Location == "GLASGOW") {
totalg += Convert.ToInt32(papr[iii].Stock);
gsm = papr[iii].Grammage;
size1 = papr[iii].Size1;
size2 = papr[iii].Size2;
commited = papr[iii].Commited;
OnOrder = papr[iii].Onorderi;
THRESH = papr[iii].Threshholdi;
}
if (s == papr[iii].Code && papr[iii].Location == "LONDON") {
totall += Convert.ToInt32(papr[iii].Stock);
gsm = papr[iii].Grammage;
size1 = papr[iii].Size1;
size2 = papr[iii].Size2;
commited = papr[iii].Commited;
OnOrder = papr[iii].Onorderi;
THRESH = papr[iii].Threshholdi;
}
if (s == papr[iii].Code && papr[iii].Location == "PARIS") {
totalp += Convert.ToInt32(papr[iii].Stock);
gsm = papr[iii].Grammage;
size1 = papr[iii].Size1;
size2 = papr[iii].Size2;
commited = papr[iii].Commited;
OnOrder = papr[iii].Onorderi;
THRESH = papr[iii].Threshholdi;
} else {}
}
Finallist.Add(new Stock_Paper_Record() {
Location = "BOTH", Code = Codes[iount], Stocki = totalg + totall + totalp + OnOrder, BBstocki = totalg, Lmstocki = totall, Ingstocki = totalp, Commited = commited, Ballance = (totalg + totall + totalp + OnOrder) - commited, Size1 = size1, Size2 = size2, Grammage = gsm, Threshholdi = THRESH, Onorderi = OnOrder
});
totalg = 0;
totall = 0;
totalp = 0;
ii++;
iount++;
}
return Finallist;
}
This will be pretty close, however, if you supply a code that there is no records for, this will not return a record for it with all 0's, but your original code did. Not sure if that matters to you or not.
private static List<Stock_Paper_Record> Get_Final_List(List<Stock_Paper_Record> Finallist, List<Stock_Paper_Record> papr, List<string> Codes, List<string> locs) {
return papr
.Where(p=>Codes.Contains(p.Location))
.GroupBy(p=>p.Code)
.Select(g=>new {
Code=g.Key,
BBstocki=g.Where(p=>p.Location=="GLASGOW").Sum(p=>Convert.ToInt32(p.Stock)),
Lmstocki=g.Where(p=>p.Location=="LONDON").Sum(p=>Convert.ToInt32(p.Stock)),
Ingstocki=g.Where(p=>p.Location=="PARIS").Sum(p=>Convert.ToInt32(p.Stock)),
Commited=g.FirstOrDefault().Commited,
Size1=g.FirstOrDefault().Size1,
Size2=g.FirstOrDefault().Size2,
Grammage=g.FirstOrDefault().Grammage,
Threshholdi=g.FirstOrDefault().Threshholdi,
Onorderi=g.FirstOrDefault().Onorderi
}).Select(g=>new Stock_Paper_Record {
Location="BOTH",
Code=g.Code,
BBstocki=g.BBstocki,
Lmstocki=g.Lmstocki,
Ingstocki=g.Ingstocki,
Commited=g.Commited,
Size1=g.Size1,
Size2=g.Size2,
Grammage=g.Grammage,
Threshholdi=g.Threshholdi,
Onorderi=g.Onorderi,
Stocki=g.BBstocki+g.Lmstocki+g.Ingstocki+g.Onorderi,
Ballance=g.BBstocki+g.Lmstocki+g.Ingstocki+g.Onorderi=g.Commited
})
.ToList();
}
I searched all over the internet to find an answer for this. I am looping through two lists (list1 and list2) with nested for loops and removing duplicate records in first list based on three criteria. If all records in these two lists match each other, I get an out of bounds error. I assume it happens when I remove all the items from the first list, and when it finally reduces to 0, and does not have any records to loop through, but putting an if statement to check the count of the first list (if inbox_emails_filtered_contacts.Count > 0) does not help either. Please let me know if any of you can tell me why this errors out.
Outlook Add-in in C#.net
for (int i = 0; i < list1.Count; i++)
{
for (int j = 0; j < list2.Count; j++)
{
if (list1.Count > 0)
{
if ((list1[i].username == registered_user)
&& (list1[i].from_email.ToLower() == list2[j].from_email.ToLower())
&& (list1[i].email_subject == list2[j].email_subject)
&& (list1[i].email_timestamp.ToLongDateString() == list2[j].email_timestamp.ToLongDateString()))
{
//Remove the duplicate email from inbox_emails_filtered_contacts
list1.RemoveAt(i);
}
}
}
}
I would suggest using while loop here. Also you need to break out of inner loop if a match is found to restart checking from the beginning.
int i = 0;
while (i < list1.Count)
{
int found = 0;
for (int j = 0; j < list2.Count; j++)
{
if ((list1[i].username == registered_user)
&& (list1[i].from_email.ToLower() == list2[j].from_email.ToLower())
&& (list1[i].email_subject == list2[j].email_subject)
&& (list1[i].email_timestamp.ToLongDateString() == list2[j].email_timestamp.ToLongDateString()))
{
//Remove the duplicate email from inbox_emails_filtered_contacts
list1.RemoveAt(i);
found = 1;
break;
}
}
if (!found)
{
i++;
}
}
here is an implementation of an Email class
class Email:IComparable<Email>
{
private static int _Id;
public Email()
{
Id = _Id++;
}
public int Id { get; private set; }
public string UserName { get; set; }
public string Body { get; set; }
public string Subject { get; set; }
public DateTime TimeStamp { get; set; }
public override int GetHashCode()
{
return UserName.GetHashCode() ^ Body.GetHashCode() ^ Subject.GetHashCode();
}
public int CompareTo(Email other)
{
return GetHashCode().CompareTo(other.GetHashCode());
}
public override string ToString()
{
return String.Format("ID:{0} - {1}", Id, Subject);
}
public override bool Equals(object obj)
{
if (obj is Email)
return CompareTo(obj as Email) == 0;
return false;
}
}
and 2 ways of getting the diff.
var list1 = new List<Email>();
var ran = new Random();
for (int i = 0; i < 50; i++)
{
list1.Add(new Email() { Body = "Body " + i, Subject = "Subject " + i, UserName = "username " + i, TimeStamp = DateTime.UtcNow.AddMinutes(ran.Next(-360, 60)) });
}
var list2 = new List<Email>();
for (int i = 0; i < 50; i++)
{
if (i % 2 == 0)
list2.Add(new Email() { Body = "Body " + i, Subject = "Subject Modifed" + i, UserName = "username " + i, TimeStamp = DateTime.UtcNow.AddMinutes(ran.Next(-360, 60)) });
else
list2.Add(new Email() { Body = "Body " + i, Subject = "Subject " + i, UserName = "username " + i, TimeStamp = DateTime.UtcNow.AddMinutes(ran.Next(-360, 60)) });
}
foreach (var item in list2.Intersect<Email>(list1))
{
Console.WriteLine(item);
}
foreach (var item in list1)
{
for (int i = 0; i < list2.Count; i++)
{
if (list2[i].Equals(item))
{
Console.WriteLine(item);
list2.RemoveAt(i);
break;
}
}
}
Console.WriteLine(list2.Count);
Use a reverse for when you iterate a list/array while removing item out of it (snippet "forr" in Visual) :
for (int i = list1.Count - 1; i >= 0; i--)
The likelyhood is that there are multiple duplicates in application_emails and so removeAt(i) is being called multiple times. Your if will never catch the case where i is the last item in a list longer than 2 and you end up removing multiple times.
Additionally you will also end up skipping emails with the remove statement. Assume i=4, if you remove at 4 index 4 will contain a new item and i will be 5 on the next iteration. You may be better off with a while loop
int i=0;
while (i < inbox_emails.Count) {
bool foundDuplicate=false;
for (int j=0;j<for (int j = 0; j < application_emails.Count; j++) {
if ((inbox_emails[i].username == registered_user)
&& (inbox_emails[i].from_email.ToLower() == application_emails[j].from_email.ToLower())
&& (inbox_emails[i].email_subject == application_emails[j].email_subject)
&& (inbox_emails[i].email_timestamp.ToLongDateString() == application[j].email_timestamp.ToLongDateString()))
{
foundDuplicate=true;
break; // This is optional but it stops the j loop from continuing as we've found a duplicate
}
}
if (foundDuplicate) {
inbox_emails.RemoveAt(i);
} else {
i++;
}
}
If this is a single thread you could just replace the list using Linq, make sure you have a using System.Linq
inbox_emails = inbox_emails.Where(i=>
i.username != registered_user
|| ! application_emails.Any(j=>
i.from_email.ToLower() == j.from_email.ToLower()
&& i.email_subject == j.email_subject
&& i.email_timestamp.ToLongDateString() == j.email_timestamp.ToLongDateString()
)
).ToList();