Search with multiple conditions? - c#

I am currently working on a search for a website and I am stuck with a problem, which doesn't even seem that hard to solve. I'm just not able to figure the solution out myself.
Situation: In the current state of my search I can sort the events to dates (I can select October for instance and it will only show the events which happen during october), for categories (The events each have categories) and even search text. Now when I select october as a month and festival as a category, I get all events occuring in october AND all festivals. I want only the festivals which occur in october. Any ideas on how I could achieve this?
This is what I've got so far:
var validEvents = new List<Item>();
var allEvents = ((LinkField)this.controlItem.Fields["Event Container"]).TargetItem.Children.ToList(); // getting the events
if (this.ddlMonths.SelectedIndex != 0 || this.ddlCategories.SelectedIndex != 0 || this.searchQuery.Text != string.Empty)
{
foreach (var currentEvent in allEvents)
{
var isValid = false;
// 1. Check for months
if (this.ddlMonths.SelectedIndex != 0)
{
// .. validation if event should be displayed
if (startDate <= monthDates[1].Date && endDate >= monthDates[0].Date)
{
isValid = true;
}
}
// 2. Check for categories
if (this.ddlCategories.SelectedIndex != 0)
{
foreach (var eventCategory in ((MultilistField) currentEvent.Fields["Categories"]).GetItems())
{
if (eventCategory["Category"].ToLower() == this.ddlCategories.SelectedValue.ToLower())
{
isValid = true;
}
}
}
// 3. Check for search query
if (this.searchQuery.Text != string.Empty)
{
var searchText = this.searchQuery.Text;
if (currentEvent["Title"].Contains(searchText) || currentEvent["Text"].Contains(searchText))
{
isValid = true;
}
}
if (isValid)
{
validEvents.Add(currentEvent);
}
}
}

Using LINQ you can combine search conditions as follows
var allEvents = ...;
IEnumerable<Item> events = allEvents;
if (ddlMonths.SelectedIndex != 0)
events = events.Where(condition1);
if (ddlCategories.SelectedIndex != 0)
events = events.Where(condition2);
if (searchQuery.Text != string.Empty)
events = events.Where(condition3);
var validEvents = events.ToList();

I would put
var isValid = true;
in line 8, then if any of the conditions is NOT met set it to false. And also skip any following check if isValid is already false.
Hope it helps!
EDIT - Complete code:
var validEvents = new List<Item>();
var allEvents = ((LinkField)this.controlItem.Fields["Event Container"]).TargetItem.Children.ToList(); // getting the events
if (this.ddlMonths.SelectedIndex != 0 || this.ddlCategories.SelectedIndex != 0 || this.searchQuery.Text != string.Empty)
{
foreach (var currentEvent in allEvents)
{
var isValid = true;
// 1. Check for months
if (this.ddlMonths.SelectedIndex != 0)
{
// .. validation if event should be displayed
if (!(isValid && startDate <= monthDates[1].Date && endDate >= monthDates[0].Date))
{
isValid = false;
}
}
// 2. Check for categories
if (this.ddlCategories.SelectedIndex != 0)
{
foreach (var eventCategory in ((MultilistField) currentEvent.Fields["Categories"]).GetItems())
{
if (!(isValid && eventCategory["Category"].ToLower() == this.ddlCategories.SelectedValue.ToLower()))
{
isValid = false;
}
}
}
// 3. Check for search query
if (this.searchQuery.Text != string.Empty)
{
var searchText = this.searchQuery.Text;
if (!(isValid && currentEvent["Title"].Contains(searchText) || currentEvent["Text"].Contains(searchText)))
{
isValid = true;
}
}
if (isValid)
{
validEvents.Add(currentEvent);
}
}
}

Related

Paragraphs formatting slow in VSTO

I am using VSTO to get some paragraphs and save their formatting in a List.The code is working fine but the problem is that this function is taking almost 50% of the execution time of my program.
It is also known that the loop is making performance slow.
I want to know that how can I optimize the time of this function.Any alternative to list or any other thing?
public static void GetFormattedParas(Range content, Driver currentDriver)
{
// TODO add check for tables row end "\r\a" words to ignore them for query
Paragraphs paras = content.Paragraphs;
List<Paragraph> paraList = paras.Cast<Paragraph>().ToList();
List<Range> Ranges = new List<Range>();
if (paraList != null)
{
paraList.RemoveAll(range => range.Range.Text == null);
paraList.RemoveAll(range => range.Range.Text.Equals("\r\a") && range.Range.Tables.Count != 0 && range.Range.Rows[1].Range.End == range.Range.End);
for (int i = 0, ParaCount = paraList.Count; i < ParaCount; i++)
{
Range range = paraList[i].Range;
if (range.Font.Shading.BackgroundPatternColorIndex != WdColorIndex.wdNoHighlight
|| range.HighlightColorIndex != WdColorIndex.wdNoHighlight
|| range.Shading.BackgroundPatternColorIndex != WdColorIndex.wdNoHighlight)
{
Ranges.Add(paraList[i].Range);
}
}
//Ranges = (from range in paraList
// where range.Range.Font.Shading.BackgroundPatternColorIndex != WdColorIndex.wdNoHighlight
// || range.Range.HighlightColorIndex != WdColorIndex.wdNoHighlight
// || range.Range.Shading.BackgroundPatternColorIndex != WdColorIndex.wdNoHighlight
// select range.Range).OrderBy(o => o.Start).ToList();
if (Ranges != null)
{
Ranges = Ranges.OrderBy(o => o.Start).ToList();
if (Ranges.Count > 0)
{
//if (Ranges.Count == 1)
//{
// currentDriver.formattedParas.Add(content);
//}
//else
//{
currentDriver.formattedParas.AddRange(Ranges);
//}
}
}
}
}

Visual Studio C# and Short-circuit evaluation

With the || Operator, Microsoft describes short circuit evaluation here Short Circuit Evaluation
However, I have the following code which seems to contradict this process:
if ((_opcLoaded || DoLoadOPC()) &&
(_tagsAdded || DoAddTags()) &&
DoWriteRecipe() &&
(DoResume()))
What I'm trying to prevent is the function DoAddTags from being called if _tagsAdded is true (DoAddTags sets _tagsAdded to true).
However, I'm finding that DoAddTags is called even when _tagsAdded is true. It's the same for _opcLoaded and DoLoadOPC. I've had to put a condition inside DoAddTags to check for _tagsAdded, which shouldn't be necessary.
Can someone explain why this is happening?
Here is the Complete Code
//
// Resume a Paused recipe
case MonitoredTasks.Resume:
Task.Factory.StartNew(() =>
{
MonitoredTask = MonitoredTasks.None;
if ((_opcLoaded || DoLoadOPC()) &&
**(_tagsAdded || DoAddTags())** &&
DoWriteRecipe() &&
(DoResume()))
{
MonitoredTask = MonitoredTasks.None;
RunningState = RecipeRunningStates.Running;
Status = CIPStatuses.Running;
}
else
{
MonitoredTask = MonitoredTasks.Resume;
}
});
break;
And the code for DoAddTags
/// <summary>
/// Adds all necessary tags to the OPC Server Manager
/// </summary>
/// <returns></returns>
bool DoAddTags()
{
bool result = false;
var oldActivity = Activity;
//
// Not doing anything OPC related?
if (Activity != CIPActivities.AddingOPCTags && !_tagsAdded && Activity != CIPActivities.StartingOPC)
{
lock (_locks[LOCK_OPC])
{
Activity = CIPActivities.AddingOPCTags;
Status = CIPStatuses.Initialising;
RecipeError = Errors.None;
try
{
//
// Reset connection and internal tags list
_serverManager.Reset();
//
// Now to add all OPC Tags - Area
CIPStatusTag = _serverManager.AddTag(_area.CIPStatusTag);
RecipeIDTag = _serverManager.AddTag(_area.RecipeIDTag);
RecipeInstructionIDTag = _serverManager.AddTag(_area.RecipeInstructionIDTag);
HandshakingTag = _serverManager.AddTag(_area.HandshakingTag);
GlobalInstructionIDTag = _serverManager.AddTag(_area.GlobalInstructionIDTag);
InstructionAttemptsTag = _serverManager.AddTag(_area.InstructionAttemptsTag);
//
// Area tags OK?
if (CIPStatusTag == null || RecipeIDTag == null || RecipeInstructionIDTag == null || HandshakingTag == null || GlobalInstructionIDTag == null || InstructionAttemptsTag == null)
{
RecipeError = Errors.InvalidAreaTags;
DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags - Invalid AREA Tags"), Sender = this });
}
else
{
VM_CIPInstruction vm = null;
bool instructionTagErrors = false;
//
// For each area instruction that is used, assig a link to the instruction
foreach (var i in _areaInstructions)
{
//
// Create a View Model for the specified area instruction : this allows us to determine the number of parameters (tags) that apply to the instruction
vm = new VM_CIPInstruction(i.Value.Instruction);
//
// Assign device reference tags
if (vm.DeviceReferencesAvailable)
{
i.Value.DeviceTag = _serverManager.AddTag(i.Value.Instruction.DeviceReferenceTag);
instructionTagErrors = i.Value.DeviceTag == null;
}
//
// For each required parameter, add tag
for (int paramNo = 1; paramNo <= vm.NoOfParams; paramNo++)
{
switch (paramNo)
{
case 1:
//
// Tag defined? Add it
if (vm.AreaInstruction.Param1Tag >= 0)
{
i.Value.Param1 = _serverManager.AddTag(i.Value.Instruction.Param1Tag);
if (i.Value.Param1 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
case 2:
//
// Tag defined? Add it
if (vm.AreaInstruction.Param2Tag >= 0)
{
i.Value.Param2 = _serverManager.AddTag(i.Value.Instruction.Param2Tag);
if (i.Value.Param2 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
case 3:
//
// Tag defined? Add it
if (vm.AreaInstruction.Param3Tag >= 0)
{
i.Value.Param3 = _serverManager.AddTag(i.Value.Instruction.Param3Tag);
if (i.Value.Param3 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
case 4:
//
// Tag defined? Add it and then check quality
if (vm.AreaInstruction.Param4Tag >= 0)
{
i.Value.Param4 = _serverManager.AddTag(i.Value.Instruction.Param4Tag);
if (i.Value.Param4 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
case 5:
//
// Tag defined? Add it and then check quality
if (vm.AreaInstruction.Param5Tag >= 0)
{
i.Value.Param5 = _serverManager.AddTag(i.Value.Instruction.Param5Tag);
if (i.Value.Param5 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
case 6:
//
// Tag defined? Add it and then check quality
if (vm.AreaInstruction.Param6Tag >= 0)
{
i.Value.Param6 = _serverManager.AddTag(i.Value.Instruction.Param6Tag);
if (i.Value.Param6 == null)
{
instructionTagErrors = true;
}
}
else
{
instructionTagErrors = true;
}
break;
}
}
if (instructionTagErrors)
{
RecipeError = Errors.InvalidInstructionTags;
DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage(String.Format("CIPRecipe.DoAddTags - Invalid Instruction {0} Tags", vm.Name)), Sender = this });
break;
}
}
//
// Any problems adding tags?
if (RecipeError == Errors.None)
{
Activity = CIPActivities.StartingOPC;
//
// Once all tags added, start OPC Server
result = _serverManager.Start();
if (!result)
{
Status = CIPStatuses.AddTagsFailed;
RecipeError = Errors.OPC;
DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags - Start of OPC failed"), Sender = this });
}
else
{
**_tagsAdded = true;**
Status = CIPStatuses.TagsAdded;
}
}
else
{
Status = CIPStatuses.AddTagsFailed;
}
}
}
catch (Exception ex)
{
RecipeError = Errors.Exception_AddTags;
DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags"), Exception = ex, Sender = this });
}
finally
{
Activity = oldActivity;
}
}
}
return Status == CIPStatuses.TagsAdded;
}
I've highlighted the relevant lines with **
On the first pass DoAddTags is executed and _tagsAdded set to TRUE- I've placed a breakpoint here, so I know it is being set. Shortly afterwards (with or without the former breakpoint) DoAddTags is again entered (on the first line) despite_doAddTags == true.
I've even set a breakpoint on the code "(_tagsAdded || DoAddTags())". _tagsAdded == true, yet DoAddTags is still entered.
So what I'm seeing is, and all the Watches/Debugging info is consistent with is that DoAddTags is being called whilst _tagsAdded == true
This code won't display the behavior you describe, the short-circuiting works just as described.
What actually happens: _tagsAdded is initially false, so DoAddTags() is called, which sets _tagsAdded to true.
Then the debugger kicks in, you inspect _tagsAdded and see it's true.
Instead step through your code using F11 and inspect or watch all relevant variables.

how to iterate collection and change value

I know this is a dumb question because you cannot modify the loop collection while in a loop, but I do need to change it. I know I must not change the referenced objects, but I have no idea how to do this.
var orders = _orderService.GetOrders(o => !o.Deleted &&
o.OrderStatus != OrderStatus.Cancelled &&
o.OrderStatus != OrderStatus.Complete);
foreach (var order in orders)
{
if (order.PaymentStatus == PaymentStatus.Paid)
{
if (order.ShippingStatus == ShippingStatus.ShippingNotRequired || order.ShippingStatus == ShippingStatus.Delivered)
{
var tempOrder = _orderService.GetOrderById(order.Id);
SetOrderStatus(tempOrder , OrderStatus.Complete, true);
}
}
}
I always get an error.
UPDATED: I changed to this
var orders = _orderService.GetOrders(o => !o.Deleted &&
o.OrderStatus != OrderStatus.Cancelled && o.OrderStatus != OrderStatus.CompletE);
List<int> orderIndex = new List<int>();
orders.ToList().ForEach(x => orderIndex.Add(x.Id));
foreach(var index in orderIndex)
{
var order = _orderService.GetOrderById(index);
if (order.PaymentStatus == PaymentStatus.Paid)
{
if (order.ShippingStatus == ShippingStatus.ShippingNotRequired || order.ShippingStatus == ShippingStatus.Delivered)
{
SetOrderStatus(order, OrderStatus.Complete, true);
}
}
}
try
int count = orders.Count; // the length of the collect : may need a different method for different collection types.
for(int i = 0; i < count; i++)
{
var current = orders[i];
// do stuff with current.
}
use for loop instead of foreach loop
for(int i=0; i<orders.Count; i++)
{
if (orders[i].PaymentStatus == PaymentStatus.Paid)
{
if (orders[i].ShippingStatus == ShippingStatus.ShippingNotRequired || orders[i].ShippingStatus == ShippingStatus.Delivered)
{
var tempOrder = _orderService.GetOrderById(orders[i].Id);
SetOrderStatus(tempOrder , OrderStatus.Complete, true);
}
}
}

Nullable Property throwing NullReferenceException on .HasValue

This line of (C#) code
if (!currentLap.S1.HasValue)
is giving me
System.NullReferenceException: Object reference not set to an instance of an object.
provided I'm sure that currentLap variable is instantiated (because it's being used a few lines before and it is a local variable) and it has following property:
private double? _s1;
[DefaultValue(null)]
[JsonConverter(typeof(ShortDoubleConverter))]
public double? S1
{
get { return _s1; }
set { _s1 = value; }
}
how can it possibly throw NullReferenceException? Can it be something to do with optimization on Release mode?
Thanks,
Stevo
EDIT:
here is full method code.
public void Update(DriverData driverData)
{
LapInfo currentLap = this.CurrentLap;
if (currentLap != null &&
this.LastDriverData != null &&
driverData.TotalLaps != this.LastDriverData.TotalLaps &&
driverData.InPits &&
driverData.Speed < 10 &&
!this.LastDriverData.InPits)
{
currentLap.Escaped = true;
}
this.LastDriverData = driverData;
if ((currentLap == null || currentLap.Lap != driverData.LapNumber) &&
!this.Laps.TryGetValue(driverData.LapNumber, out currentLap))
{
currentLap = new LapInfo() { Lap = driverData.LapNumber, Parent = this, Class = driverData.Class };
this.Laps.Add(driverData.LapNumber, currentLap);
int lapsCount = 0, completedDriverLaps = 0, cleanLaps = 0;
this.TotalLaps = driverData.TotalLaps;
//if it's not the first lap
if (driverData.TotalLaps > 0)
{
//previous lap
if (this.CurrentLap == null || !this.CurrentLap.Escaped)
{
this.CompletedLaps++;
if (this.CurrentLap == null || !this.CurrentLap.MaxIncident.HasValue)
this.CleanLaps++;
}
}
foreach (DriverLapsInfo laps in this.Parent.LapsByVehicle.Values)
{
lapsCount += laps.TotalLaps;
completedDriverLaps += laps.CompletedLaps;
cleanLaps += laps.CleanLaps;
}
this.Parent.Parent.SetLapsCount(driverData, lapsCount, driverData.Class, completedDriverLaps, cleanLaps);
}
this.CurrentLap = currentLap;
//add incidents
if (driverData.Incidents != null)
{
foreach (IncidentScore incident in driverData.Incidents)
{
this.CurrentLap.MaxIncident = Math.Max(this.CurrentLap.MaxIncident ?? 0, incident.Strength);
this.CurrentLap.Incidents++;
this.Incidents++;
}
}
LapInfo previousLap = null;
if ((this.PreviousLap == null || this.PreviousLap.Lap != driverData.TotalLaps) &&
this.Laps.TryGetValue(driverData.TotalLaps, out previousLap))
{
this.PreviousLap = previousLap;
if (!this.PreviousLap.Date.HasValue)
{
this.PreviousLap.Date = DateTime.UtcNow;
}
}
if (currentLap.Position == 0)
currentLap.Position = driverData.Position;
if (driverData.CurrentS1 > 0)
{
**if (!currentLap.S1.HasValue)**
{
this.UpdateBestS1(driverData.BestS1);
this.Parent.Parent.UpdateBestS1(driverData.BestS1, driverData.UniqueName);
currentLap.UpdateS1(driverData.CurrentS1, driverData);
//reset the best split set at the finish line
if (this.PreviousLap != null && this.PreviousLap.SplitBest < 0)
this.PreviousLap.SplitBest = 0;
}
if (driverData.CurrentS2.HasValue && driverData.CurrentS1.HasValue && !currentLap.S2.HasValue)
{
double s2 = driverData.CurrentS2.Value - driverData.CurrentS1.Value;
this.UpdateBestS2(s2);
this.Parent.Parent.UpdateBestS2(s2, driverData.UniqueName);
currentLap.UpdateS2(s2, driverData);
}
}
if (this.PreviousLap != null)
{
if (driverData.LastLap > 0)
{
if (!this.PreviousLap.S3.HasValue && driverData.LastS2.HasValue)
{
double s3 = driverData.LastLap.Value - driverData.LastS2.Value;
this.UpdateBestS3(s3);
this.Parent.Parent.UpdateBestS3(s3, driverData.UniqueName);
this.PreviousLap.UpdateS3(s3, driverData);
}
if (!this.PreviousLap.LapTime.HasValue)
{
double? bestLap = this.Parent.Parent.BestLap;
this.PreviousLap.UpdateLapTime(driverData, 0);
this.Parent.Parent.UpdateBestLap(this.PreviousLap, driverData.BestLap, driverData);
this.UpdateBestLap(driverData.BestLap, this.PreviousLap);
this.PreviousLap.UpdateLapTime(driverData, bestLap);
}
}
else
{
if (this.PreviousLap.SplitBest.HasValue)
this.PreviousLap.UpdateBestSplit();
if (this.PreviousLap.SplitSelf.HasValue)
this.PreviousLap.UpdateSelfSplit();
}
}
if (driverData.InPits)
{
switch (driverData.Sector)
{
case Sectors.Sector1:
if (previousLap != null)
previousLap.InPits = true;
break;
case Sectors.Sector3:
currentLap.InPits = true;
break;
}
}
//lap to speed
if (currentLap.TopSpeed < driverData.Speed)
{
driverData.TopSpeedLap = driverData.Speed;
currentLap.UpdateTopSpeed(driverData.Speed);
}
else
driverData.TopSpeedLap = currentLap.TopSpeed;
//overall top speed
if (this.TopSpeed < driverData.Speed)
{
driverData.TopSpeed = driverData.Speed;
this.TopSpeed = driverData.Speed;
this.Parent.Parent.UpdateTopSpeed(this.TopSpeed, driverData);
}
else
driverData.TopSpeed = this.TopSpeed;
}
There is no way on earth the code can make it to that line and currentLap beeing null.
Or am I going crazy? :)
.HasValue will not throw if the nullable reference is null, but a.b.HasValue will if a is null.
I suspect that currentLap == null. I know you say you're sure that currentLap is not null, but I think that's the most likely explanation. Can you post more code?
Update:
Thanks for posting your code.
This doesn't throw:
void Main() {
var f = new Foo();
Console.WriteLine (f.S1);
Console.WriteLine (f.S1.HasValue);
}
class Foo {
private double? _s1 = null;
public double? S1 {
get { return _s1; }
set { _s1 = value; }
}
}
Could you try to create a minimal reproduction? (minimal code that exhibits the issue)
Maybe have a look at the previous line of code :) - debugger often highlights the next line after the one where the NullReferenceException was actually thrown.

ObjectListView's TreeListView cell editing very very slow

I am using a TreeListView (ObjectListView) http://objectlistview.sourceforge.net/cs/index.html - and populated it with a number of items. One of the columns I made editable on double click for user input. Unfortunately, the editing is extremely slow and going from one cell edit in the Qty column (see picture further below) to the next cell edit takes about 5-10 seconds each time. Also, the cell editor takes a while to appear and disappear. Below is the code I use to populate the TreeListView:
TreeListView.TreeRenderer renderer = this.treeListView.TreeColumnRenderer;
renderer.LinePen = new Pen(Color.Firebrick, 0.5f);
renderer.LinePen.DashStyle = DashStyle.Solid;
renderer.IsShowLines = true;
treeListView.RowFormatter = delegate(OLVListItem olvi)
{
var item = (IListView)olvi.RowObject;
if (item.ItemType == "RM")
olvi.ForeColor = Color.LightSeaGreen;
};
treeListView.CanExpandGetter = delegate(object x)
{
var job = x as IListView;
if (job != null)
{
if (job.ItemType == "PA" || job.ItemType == "JC")
{
var rm = job.ItemPart.GetRawMaterial();
var subParts = job.ItemPart.SubParts.Where(v => v != null).ToList();
if (rm.Count > 0|| subParts.Count > 0)//
return true;
}
}
return false;
};
this.treeListView.ChildrenGetter = delegate(object x)
{
try
{
var job = x as IListView;
if (job != null)
{
if (job.ItemType == "PA" || job.ItemType == "JC")
{
var part = job.ItemPart;
var rm = part.GetRawMaterial();
var subParts = part.SubParts.Where(v => v != null).ToList();
var items = new List<IListView>();
items.AddRange(subParts.GetRange(0, subParts.Count).ToList<IListView>());
items.AddRange(rm.GetRange(0, rm.Count).ToList<IListView>());
return items;
}
}
return null;
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(this, ex.Message, "ObjectListViewDemo", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
};
var lItems= jobs.ToList<IListView>();
treeListView.SetObjects(lItems );
Expand(lItems[0]);
treeListView.RebuildAll(true);
}
public void Expand(object expItem)
{
treeListView.ToggleExpansion(expItem);
foreach (var item in treeListView.GetChildren(expItem))
{
Expand(item);
}
}
Here is a picture of the cell editing:
Why is the editing so very slow? Am I doing something wrong? What can I do to make it faster?
In your delegates you're using linear searches and several list copies (also linear). And this is for each item.
Bad performance is to be expected.
If you want to improve on this, you can pre-calculate the results instead.

Categories

Resources