MongoDB $or many orders of magnitude slower than single queries - performance

When querying 10K objects, it appears that querying each object individually with a find_one is much faster than $or-ing the queries together, which doesn't make much sense. Is there something wrong with the following making things slow? The query seems to hang for a while for the first 200 or so objects, and then finds all the rest very quickly.
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
public class MongoOrVsSingleQuery {
public static void main(String[] args) throws Exception {
MongoClient mc = new MongoClient();
mc.getDB("foo").dropDatabase();
DBCollection foo = mc.getDB("foo").getCollection("foo");
DBObject index = new BasicDBObject("a", 1);
index.put("b", 1);
foo.ensureIndex(index);
List<DBObject> lo = new LinkedList<DBObject>();
for (int i = 1; i < 10001; i++) {
DBObject o = new BasicDBObject("a", i);
o.put("b", 1);
lo.add(o);
}
System.out.println("insert: " + new Date());
foo.insert(lo);
for (DBObject o: lo) {
o.removeField("_id");
}
DBObject query = new BasicDBObject("$or", lo);
System.out.println("find one: " + new Date());
for (DBObject o: lo) {
foo.findOne(o).get("a");
}
System.out.println("find: " + new Date());
DBCursor dbc = foo.find(query);
for (DBObject o: dbc) {
if ((int) o.get("a") % 100 == 0) {
System.out.println("find obj: " + o.get("a") + " " + new Date());
}
}
System.out.println("done: " + new Date());
}
}
Output:
insert: Tue Nov 19 07:16:02 PST 2013
find one: Tue Nov 19 07:16:02 PST 2013
find: Tue Nov 19 07:16:05 PST 2013
find obj: 100 Tue Nov 19 07:16:08 PST 2013
find obj: 200 Tue Nov 19 07:21:22 PST 2013
find obj: 300 Tue Nov 19 07:21:22 PST 2013
*snip*
find obj: 9900 Tue Nov 19 07:21:22 PST 2013
find obj: 10000 Tue Nov 19 07:21:22 PST 2013
done: Tue Nov 19 07:21:22 PST 2013
During the query, this is typical output of currentOp():
~$ mongo
MongoDB shell version: 2.4.3
connecting to: test
> use foo
> db.currentOp()
{
"inprog" : [
{
"opid" : 40221,
"active" : true,
"secs_running" : 241,
"op" : "getmore",
"ns" : "foo.foo",
"query" : {
"$msg" : "query not recording (too large)"
},
"client" : "127.0.0.1:58696",
"desc" : "conn7",
"threadId" : "0x7fef961f8700",
"connectionId" : 7,
"locks" : {
"^" : "r",
"^foo" : "R"
},
"waitingForLock" : false,
"numYields" : 124,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(390668733),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(195362976),
"w" : NumberLong(0)
}
}
}
]
}
> db.version()
2.4.3

Related

Reduce list of interval(begin & end time) to get maximum no of non-overlapping function that we can attend in a day

I am creating a Java 8 program which gives the maximum number of functions that a person can attend in a day. i.e) A person can be present in only one function at any given time interval.
I tried coding to get the solution but was not able to find where I am lagging, Please help me out.
Sample input :
1 //Number of input days
5 //number of functions in a day
reception 14:00 16:00
babyShowering 12:00 14:30
innaguration 14:00 16:30
wedding 12:30 13:30
politicalMeeting 13:30 15:00
Sample/expected output :
2
package problems.functionScheduler;
import static java.time.temporal.ChronoUnit.MINUTES;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Solution {
public class Interval {
public LocalTime begin;
public LocalTime end;
public Interval(LocalTime begin, LocalTime end) {
super();
this.begin = begin;
this.end = end;
}
public LocalTime getBegin() {
return begin;
}
public void setBegin(LocalTime begin) {
this.begin = begin;
}
public LocalTime getEnd() {
return end;
}
public void setEnd(LocalTime end) {
this.end = end;
}
public long timeDifference() {
return MINUTES.between(begin, end);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Solution solutionObject = new Solution();
int t = scanner.nextInt();
IntStream.rangeClosed(1, t).forEach(i -> {
// System.out.println("This is the " + i + "th iteration :");
List<Interval> intervalList = new ArrayList<>();
int n = scanner.nextInt();
scanner.nextLine();
IntStream.rangeClosed(1, n).forEach(j -> {
// System.out.println("This is the " + j + "th value from the " + i + "th
// iteration :");
String[] values = scanner.nextLine().split("\\s+");
// System.out.println(values[0]);
// System.out.println(values[1]);
// System.out.println(values[2]);
intervalList.add(solutionObject.new Interval(LocalTime.parse(values[1]), LocalTime.parse(values[2])));
});
// sorting the list
List<Interval> temp = intervalList.stream()
.filter(interval -> !interval.getBegin().equals(interval.getEnd()))
.sorted(Comparator.comparing(Interval::timeDifference))
// .sorted(Comparator.comparing(Interval::getBegin))
// .sorted(Comparator.comparing(Interval::getEnd))
.collect(Collectors.toList());
// calculateMaxCount(temp.get(0), temp.subList(1, temp.size()));
List<Interval> temp1 = temp;
System.out.println(calculateMaximumCount(temp, temp1));
// temp.forEach(inte -> System.out.println("The begin is "+inte.getBegin()+" and the end is "+inte.getEnd()));
// temp.stream().reduce(new Interval(LocalTime.parse("00:00", "00:00")), (int1, int2) -> Solution.isOverlapping(int1, int2));
// new Interval(LocalTime.parse("00:00"), LocalTime.parse("00:00"));
});
}
private static int calculateMaximumCount(List<Interval> temp, List<Interval> temp1) {
int maximumCount = 0;
for (int m = 0; m < temp.size(); m++) {
int count = 0;
for (int l = m + 1; l < temp1.size(); l++) {
if (isNotOverlapping(temp.get(m), temp1.get(l))) {
count++;
}
}
if (count > maximumCount) {
maximumCount = count;
}
}
return maximumCount;
}
private static boolean isNotOverlapping(Interval interval1, Interval interval2) {
return !interval2.getBegin().isBefore(interval1.getEnd());
}
}
Sample input :
1 //Number of input days
5 //number of functions in a day
reception 14:00 16:00
babyShowering 12:00 14:30
innaguration 14:00 16:30
wedding 12:30 13:30
politicalMeeting 13:30 15:00
Sample/expected output :
2

Drools 6.5 Final CEP (Fusion) stability and performance problems

I am trying to see the max EPS capacity of Drools CEP. I am using 8 core 2.6 GHz CPU with 16 GB RAM. I am testing just 200 EPS with 2 rules. Drools starts good but later (within 5 to 15 minutes) it stucks or starts NOT TO FIRE
I have tested with fireAllRules and fireUntilHalt.
My Test Code:
package com.anet.correlation;
public class TestRealCase {
public static void main(String[] args) {
Main.initTest();
RulesRegistery.starttime = System.currentTimeMillis();
if (RuleRunTimeRegistery.isFireuntilHalt) {
Thread t = new Thread(new FT());
t.start();
}
int i = 0;
if (Main.ruleEngine != null) {
while (true) {
GeneralCorrelationObject ao1 = new GeneralCorrelationObject();
ao1.setLOGTYPE("Firewalls");
ao1.setSourceMachine("1.2.3.4" + (i % 500));
ao1.setDestinationPort(i);
Main.ruleEngine.evaluate(ao1);
i++;
if (i % RulesRegistery.EPS == 0)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
My DRL File
import com.anet.correlation.*;
import java.util.*;
import com.anet.ntLog.collector.*;
import com.anet.alarm.*;
import com.anet.util.*;
import com.anet.correlation.operators.*;
import com.anet.correlation.utils.*;
declare GeneralCorrelationObject
#role(event)
#expires( 1200s )
end
rule "Port Scan_Port Scan_16"
salience 0
no-loop
when
$map1: Map()
from accumulate(
generalcorrelationobject1:GeneralCorrelationObject(LOGTYPE=='Firewalls') over window:time( 1m )
,init( Map m = new HashMap();Hashtable ht= new Hashtable(); ),
action(
if(generalcorrelationobject1.getSourceMachine()==null)
{
return;
}
String key="SourceMachine="+generalcorrelationobject1.getSourceMachine();
List list = (List)m.get(key);
if( list == null )
list = new ArrayList();
Object val1=generalcorrelationobject1.getDestinationPort();
String value1;
if (val1 instanceof Integer)
value1=val1+"";
else
value1=(String)val1;
String not_key=value1;
if (ht.containsKey(key)){
Hashtable ht_hash=(Hashtable)ht.get(key);
Object ht_val=ht_hash.get(not_key);
String ht_value;
if (ht_val instanceof Integer)
ht_value=ht_val+"";
else
ht_value=(String)ht_val;
if (!not_key.equalsIgnoreCase(ht_value)){
ht_hash.put(not_key, not_key);
ht.put(key, ht_hash);
list.add( generalcorrelationobject1 );
}
}
else{
Hashtable ht_hash=new Hashtable();
ht_hash.put(not_key, not_key);
ht.put(key, ht_hash);
list.add( generalcorrelationobject1 );
}
m.put(key,list);),
result( m )
)
then
/*
if ((new CheckListSize()).check($map1,10)){
System.out.println("Done");
}
*/
Iterator s = $map1.keySet().iterator();
while (s.hasNext()) {
String key = (String) s.next();
List list = (List) $map1.get(key);
System.out.println(key+" : "+list.size());
}
end
rule "Port eee Scan_161"
salience 100
no-loop
when
ee:GeneralCorrelationObject()
then
if (RulesRegistery.numberofsingleruleexecution % RulesRegistery.printEPS == 0) {
System.out.println(ee.getSourceMachine());
}
RulesRegistery.numberofsingleruleexecution++;
end
RuleEngine Code
package com.anet.correlation;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.ReleaseId;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.internal.builder.conf.RuleEngineOption;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.api.io.ResourceType;
public final class RulesEngine {
KieSession ksession;
KieBuilder kbuilder;
public static String header = null;
public RulesEngine(boolean b) {
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
kfs.write("src/main/resources/bench.drl", getRule());
this.kbuilder = ks.newKieBuilder(kfs);
this.kbuilder.buildAll();
if (this.kbuilder.getResults().hasMessages(new Message.Level[] { Message.Level.ERROR })) {
throw new IllegalArgumentException(this.kbuilder.getResults().toString());
}
ReleaseId relId = this.kbuilder.getKieModule().getReleaseId();
KieContainer kcontainer = ks.newKieContainer(relId);
KieBaseConfiguration kbconf = ks.newKieBaseConfiguration();
kbconf.setOption(EventProcessingOption.STREAM);
kbconf.setOption(RuleEngineOption.PHREAK);
// kbconf.setOption(RuleEngineOption.RETEOO);
System.out.println("KB " + kbconf.getProperty("drools.ruleEngine"));
KieBase kbase = kcontainer.newKieBase(kbconf);
KieSessionConfiguration ksconf = ks.newKieSessionConfiguration();
this.ksession = kbase.newKieSession(ksconf, null);
}
String readFile(String fileName) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
String rule = (sb.toString());
System.out.println("New Final");
System.out.println(rule);
return rule;
} finally {
br.close();
}
}
public String getRule() {
try {
return readFile(".." + File.separator + "rules" + File.separator + "all.drl");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void evaluate(GeneralCorrelationObject message) {
if (message == null) {
System.out.println("message null ");
return;
}
if (ksession == null) {
System.out.println("ksession null ");
return;
}
try {
Long n = System.currentTimeMillis();
if (RulesRegistery.numberofrules % RulesRegistery.printEPS == 0) {
System.out.println("Inserting Objects " + RulesRegistery.numberofrules + " EPS : "
+ (RulesRegistery.numberofrules / ((n - RulesRegistery.starttime) / 1000)) + " : Total time "
+ ((n - RulesRegistery.starttime) / (1000 * 60)) + " : " + new Date());
}
ksession.insert(message);
if (RulesRegistery.numberofrules % RulesRegistery.printEPS == 0) {
System.out.println("Inserted Objects " + RulesRegistery.numberofrules + " EPS : "
+ (RulesRegistery.numberofrules / ((n - RulesRegistery.starttime) / 1000)) + " : Total time "
+ ((n - RulesRegistery.starttime) / (1000 * 60)) + " : " + new Date());
}
if (!RuleRunTimeRegistery.isFireuntilHalt) {
if (RulesRegistery.numberofrules % RulesRegistery.printEPS == 0) {
System.out.println("Running Rules " + RulesRegistery.numberofrules + " EPS : "
+ (RulesRegistery.numberofrules / ((n - RulesRegistery.starttime) / 1000))
+ " : Total time " + ((n - RulesRegistery.starttime) / (1000 * 60)) + " : "
+ new Date());
}
ksession.fireAllRules();
if (RulesRegistery.numberofrules % RulesRegistery.printEPS == 0) {
System.out.println("Runned Rules " + RulesRegistery.numberofrules + " EPS : "
+ (RulesRegistery.numberofrules / ((n - RulesRegistery.starttime) / 1000))
+ " : Total time " + ((n - RulesRegistery.starttime) / (1000 * 60)) + " : "
+ new Date());
}
}
RulesRegistery.numberofrules++;
RuleRunTimeRegistery.lasttiem = n;
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
Unless I've missed it: there isn't a retract statement in your code. This means that you keep inserting objects, with the usual result, after some time.
Retract facts as soon they aren't needed any more in any of your rules.

how do i create a hierarchy list from a list of class<T> using LINQ

i have the below data , employee column consider as parent and each employee have invoice as child and each invoice have invoicedetails as subchild.
i have binded this data into a list of class. now i want create hierarchy list from this list using LINQ
parent---> child--->subchild
Employee-Invoice--->InvoiceDetails
List Data:
Employee invoice InvoiceDetails jan feb Mar Apr
E1 I1 ID1 1 2 10 5
E1 I1 ID2 1 3 11 6
E1 I1 ID3 1 4 12 7
E1 I2 ID1 1 5 13 8
E1 I2 ID2 1 6 14 9
E1 I2 ID3 1 7 15 10
E2 I1 ID1 1 8 16 11
E2 I1 ID2 1 10 17 12
Output :
E1
--I1
--ID1 1 2 10 5
--ID2 1 3 11 6
--ID3 1 4 12 7
-I2
--ID1 1 5 13 8
--ID2 1 6 14 9
--ID3 1 7 15 10
E2
--I1
--ID1 1 8 16 11
--ID2 1 10 17 12
Please let me know if you need more clarification.
var dataTree = employeeInvoiceDetails.GroupBy(__item => __item.Employee, __item => __item, (__key, __items) => new { Employee = __key, Invoices = __items.GroupBy(___item => ___item.invoice) });
foreach (var employe in dataTree)
{
Console.WriteLine("--{0}", employe.Employee);
foreach (var invoice in employe.Invoices)
{
Console.WriteLine("\t--{0}", invoice.Key);
foreach (var employeeInvoiceDetail in invoice)
Console.WriteLine("\t\t--{0} {1} {2} {3} {4}", employeeInvoiceDetail.InvoiceDetails, employeeInvoiceDetail.jan, employeeInvoiceDetail.feb, employeeInvoiceDetail.Mar, employeeInvoiceDetail.Apr);
}
}
I've assumed that your classes look like this:
public class Employee
{
public string Id;
public List<Invoice> Invoices;
}
public class Invoice
{
public string Id;
public List<InvoiceDetails> InvoiceDetails;
}
public class InvoiceDetails
{
public string Id;
}
And I've assumed that your source data is like this:
var source = new []
{
new { Employee = "E1", Invoice = "I1", InvoiceDetails = "ID1" },
new { Employee = "E1", Invoice = "I1", InvoiceDetails = "ID2" },
new { Employee = "E1", Invoice = "I1", InvoiceDetails = "ID3" },
new { Employee = "E1", Invoice = "I2", InvoiceDetails = "ID1" },
new { Employee = "E1", Invoice = "I2", InvoiceDetails = "ID2" },
new { Employee = "E1", Invoice = "I2", InvoiceDetails = "ID3" },
new { Employee = "E2", Invoice = "I1", InvoiceDetails = "ID1" },
new { Employee = "E2", Invoice = "I1", InvoiceDetails = "ID2" },
};
Then this is the query you need:
var employees =
(
from x in source
group x by x.Employee into gxs
select new Employee()
{
Id = gxs.Key,
Invoices =
(
from y in gxs
group y by y.Invoice into gys
select new Invoice()
{
Id = gys.Key,
InvoiceDetails =
(
from z in gys
select new InvoiceDetails()
{
Id = z.InvoiceDetails,
}
).ToList()
}
).ToList()
}
).ToList();
That gives me this result:

Algorithm to find continuous days in a week

The user can select any number of week days from a list. An algorithm shall find the longest continuous group of selected days. The start day can be after the end day, if the group spans two weeks. If it makes it simpler, only a group of at least 3 days needs to be detected. With crossing the week border, this makes for a maximum of one group. (There can be no two groups of 3 days within a week that are not connected.)
For example, if the user selects Monday, Tuesday, Wednesday and Saturday from a list, the display should be something like "Monday-Wednesday and Saturday".
Another example is: Wed, Fri, Sat, Sun, Mon -> "Wed, Fri-Mon".
Is there an efficient algorithm for that, preferrably in C# or a similar language? My C# hackwork is now over a page long (incl. few comments) and still not finished.
Use this answer, slightly changed:
Use a modified version of dtb's GroupAdjacentBy which accepts a minCount as a parameter:
public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate, int minCount)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
var list = new List<T> { e.Current };
var pred = e.Current;
while (e.MoveNext())
{
// if adjacent, add to list
if (predicate(pred, e.Current))
{
list.Add(e.Current);
}
else
{
// otherwise return previous elements:
// if less than minCount elements,
// return each element separately
if (list.Count < minCount)
{
foreach (var i in list)
yield return new List<T> { i };
}
else
{
// otherwise return entire group
yield return list;
}
// create next group
list = new List<T> { e.Current };
}
pred = e.Current;
}
yield return list;
}
}
}
and change the criteria for GroupAdjacentBy to group on week transitions also:
// week starts with Monday, so this should
// represent: Wed, Fri, Sat, Sun, Mon
int[] array = new int[] { 1, 2, 4, 5, 6, 0 };
Func<int, int, bool> adjacentCriteria = (x, y) => (x+1==y) || (x==6 && y==0);
string result = string.Join(", ", array
.GroupAdjacentBy(adjacentCriteria, 3)
.Select(g => new int[] { g.First(), g.Last() }.Distinct())
.Select(g => string.Join("-", g)));
Console.WriteLine(result); // output: 1, 2, 4-0
I've finished my version of it. It's a bit longer than the other one, but then again it also handles the text representation and does exactly this task. How about that?
using System;
using System.Text;
namespace WeekMathTest
{
class Program
{
static void Main(string[] args)
{
string[] weekDayNames = new string[] {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
};
WeekDays weekDays = WeekDays.Monday | WeekDays.Tuesday | WeekDays.Thursday | WeekDays.Saturday | WeekDays.Sunday;
Console.WriteLine(WeekDayGroup(weekDays, weekDayNames));
}
static string WeekDayGroup(WeekDays weekDays, string[] weekDayNames)
{
int groupStart = 0, groupEnd = 0, groupLength = 0;
int maxGroupStart = 0, maxGroupEnd = 0, maxGroupLength = 0;
// Iterate all days in a repeated range
// (Sat/Sun doesn't need to be repeated or it would be in the first group)
for (int day = 1; day <= 7 + 5; day++)
{
// Is this day set?
int bitValue = 1 << ((day - 1) % 7);
bool daySet = ((int) weekDays & bitValue) != 0;
if (daySet)
{
if (groupStart == 0)
{
// First day set, remember it as group start
groupStart = day;
groupEnd = day;
groupLength = 1;
}
else
{
// Group has already been started, set new end
groupEnd = day;
groupLength = groupEnd - groupStart + 1;
if (groupLength == 7)
{
// Seen every day of the week, stop here
break;
}
}
}
else
{
if (groupLength >= 3 && groupLength > maxGroupLength)
{
// Group was long enough and longer than the last one, save it
maxGroupStart = groupStart;
maxGroupEnd = groupEnd;
maxGroupLength = groupLength;
}
// Reset operation variables
groupStart = 0;
groupEnd = 0;
groupLength = 0;
}
}
// Final check
if (groupLength >= 3 && groupLength > maxGroupLength)
{
// Group was long enough and longer than the last one, save it
maxGroupStart = groupStart;
maxGroupEnd = groupEnd;
maxGroupLength = groupLength;
}
// Clear all group days from the original value
for (int day = maxGroupStart; day <= maxGroupEnd; day++)
{
int bitValue = 1 << ((day - 1) % 7);
weekDays = (WeekDays) ((int) weekDays & ~bitValue);
}
// Generate output string
StringBuilder sb = new StringBuilder();
for (int day = 1; day <= 7; day++)
{
int bitValue = 1 << ((day - 1) % 7);
bool daySet = ((int) weekDays & bitValue) != 0;
if (daySet)
{
if (sb.Length > 0) sb.Append(", ");
sb.Append(weekDayNames[day - 1]);
}
else if (day == maxGroupStart)
{
if (sb.Length > 0) sb.Append(", ");
sb.Append(weekDayNames[day - 1]);
sb.Append("-");
sb.Append(weekDayNames[(maxGroupEnd - 1) % 7]);
}
}
return sb.ToString();
}
[Flags]
enum WeekDays
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
}
}

Problem with sorting objects

I have a collection of Car:
var cars = new List<Car>();
cars.Add(new Car { ProductionDate = new DateTime(2011,02,02) });
cars.Add(new Car { ProductionDate = new DateTime(2011, 01, 01) });
cars.Add(new Car { ProductionDate = new DateTime(2011,04,04,04,04,04) });
cars.Add(new Car { ProductionDate = new DateTime(2011, 03, 03, 3, 3, 3) });
I need to sort it by ProductionDate.
Result should be that at first I will have cars with date with time, so it should be car with 2011, 03, 03, 3, 3, 3 as production date, and at the end should be car with 2011, 02, 02 as production date. Second should be car with 2011, 04, 04, 04, 04, 04, and the third with 2011, 02, 02.
I can do it by using foreach but I believe that there is nicer way to do it.
cars.Sort((p, q) => {
var tm1 = p.ProductionDate.TimeOfDay;
var tm2 = q.ProductionDate.TimeOfDay;
if (tm1.Ticks == 0) {
if (tm2.Ticks == 0) {
return p.ProductionDate.CompareTo(q.ProductionDate);
}
return 1;
} else if (tm2.Ticks == 0) {
return -1;
} else {
return p.ProductionDate.CompareTo(q.ProductionDate);
}
});
But remember: what happens if a car is built at 0:00? A DateTime is made of a Data+Time. You can't see if the Time part is missing!
I'll add that if you need to use the Enumerable.OrderBy, then you can use my lamdba function with the LambdaComparer that you can find around the internet (as suggested by sll)
TimeSpan zeroTime = new TimeSpan(0);
var sortedCars = cars.OrderBy(c => c.ProductionDate.TimeOfDay.Equals(zeroTime) ? 1 : 0)
.ThenBy(c => c.ProductionDate)
.ToList();
I have something like that
var carsWithoutProductionTime = from car in cars
where car.ProductionDate.Hour == 0
orderby car.ProductionDate
select car;
var carsWithProductionTime = from car in cars
where car.ProductionDate.Hour != 0
orderby car.ProductionDate
select car;
var mergedCars = carsWithProductionTime.Union(carsWithoutProductionTime);
but It looks ugly. I would like to see something more sophisticated :)

Resources