I have an array with this data (ID, Time, and Name):
var array = new[]
{
new { ID = 1, Time = DateTime.ParseExact("12:01", "HH:mm", null), Name = "Peter" },
new { ID = 2, Time = DateTime.ParseExact("12:06", "HH:mm", null), Name = "James" },
new { ID = 3, Time = DateTime.ParseExact("12:03", "HH:mm", null), Name = "Jackie" },
new { ID = 4, Time = DateTime.ParseExact("12:08", "HH:mm", null), Name = "Peter" },
new { ID = 5, Time = DateTime.ParseExact("12:05", "HH:mm", null), Name = "James" },
new { ID = 6, Time = DateTime.ParseExact("12:07", "HH:mm", null), Name = "Peter" },
};
The following statement on the array produces the correct result:
var result = array.OrderBy(x => x.Time).GroupBy(x => x.Name)
.SelectMany(x => x).ToArray();
The result:
Time: 2013/3/6 12:01:00, Name: Peter
Time: 2013/3/6 12:07:00, Name: Peter
Time: 2013/3/6 12:08:00, Name: Peter
Time: 2013/3/6 12:03:00, Name: Jackie
Time: 2013/3/6 12:05:00, Name: James
Time: 2013/3/6 12:06:00, Name: James
But when I use the same statement with EF and SQL Server, the order is wrong:
Time: 2013/3/6 12:03:00, Name: Jackie
Time: 2013/3/6 12:06:00, Name: James
Time: 2013/3/6 12:05:00, Name: James
Time: 2013/3/6 12:07:00, Name: Peter
Time: 2013/3/6 12:01:00, Name: Peter
Time: 2013/3/6 12:08:00, Name: Peter
Here is the SQL EF generates:
SELECT
[Extent2].[Id] AS [Id],
[Extent2].[Time] AS [Time],
[Extent2].[Name] AS [Name]
FROM (SELECT DISTINCT
[Extent1].[Name] AS [Name]
FROM [dbo].[testt1] AS [Extent1] ) AS [Distinct1]
INNER JOIN [dbo].[testt1] AS [Extent2]
ON ([Distinct1].[Name] = [Extent2].[Name]) OR
(([Distinct1].[Name] IS NULL) AND ([Extent2].[Name] IS NULL))
There is no order by clause.
What did I forget? Is this a bug of EF?
How to get the same result from EF as from the array?
Just like in SQL:
First group, then order:
var result = array.GroupBy(x => x.Name)
.Select(x => x.OrderBy(y => y.Time))
.SelectMany(x => x)
.ToArray();
But in your case I don't see why you would need the group at all. Every time seems to be different, so a simpler version that yields the same result (at least with your test data) would be:
var result = array.OrderBy(x => x.Name)
.ThenBy(y => y.Time)
.ToArray();
Related
This question already has answers here:
How to sort an array of timestamps using lodash in desc order
(7 answers)
Closed 3 years ago.
I have this JavaScript object:
var items = [
{
name: "order 2",
date: "2020-02-01T13:50:04.869Z",
},
{
name: "order 3",
date: "2020-03-01T13:50:04.869Z",
},
{
name: "order 1",
date: "2020-01-01T13:50:04.869Z",
},
];
And I want to get the array ["order 1", "order 2", "order 3"] where the names are taken and are ordered by date.
What I tried so far is (using lodash):
var array = _.map(
_.sortBy(items, function(el) { return el.date; }),
function(el) { return el.name; }
);
Which is sorting the items, but my date is recognized as string and not as date time.
How do I sort this per date?
Parse the date in the _.sortBy() iteratee function, and set the iteratee of _.map() to name:
var items = [{"name":"order 2","date":"2020-02-01T13:50:04.869Z"},{"name":"order 3","date":"2020-03-01T13:50:04.869Z"},{"name":"order 1","date":"2020-01-01T13:50:04.869Z"}];
var array = _.map(
_.sortBy(items, o => Date.parse(o.date)),
'name'
);
console.log(array);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
you can try with that:
var items = [
{
name: "order 2",
date: "2020-02-01T13:50:04.869Z",
},
{
name: "order 3",
date: "2020-03-01T13:50:04.869Z",
},
{
name: "order 1",
date: "2020-01-01T13:50:04.869Z",
},
];
var names = items .sort(function compare(a, b) {
var dateA = new Date(a.date);
var dateB = new Date(b.date);
return dateA - dateB;
}).map(v => v.name);
console.log(names);
I have been trying to create a Kendo grid with dynamic column values based on a date item as part of the response data.
The data I have looks like this:
[
{ Date: '01-01-2018', Name: 'Foo', Value: 1000},
{ Date: '02-01-2018', Name: 'Foo', Value: 2000},
{ Date: '03-01-2018', Name: 'Foo', Value: 3000},
{ Date: '01-01-2018', Name: 'Bar', Value: 1400},
{ Date: '02-01-2018', Name: 'Bar', Value: 2000},
{ Date: '03-01-2018', Name: 'Bar', Value: 5000}
]
My intended structure for the grid is the following:
| Name | Jan | Feb | Mar |
|------|------|------|------|
| Foo | 1000 | 2000 | 3000 |
| Bar | 1400 | 2000 | 5000 |
I had a look at https://docs.telerik.com/kendo-ui/controls/data-management/grid/how-to/various/create-with-dynamic-columns-and-data-types but it was not quite what I was trying to do and it required that I have the columns sent as part of the response.
I am working with a wrapper for GridOptions that populates the columns through a staticly defined json. Since my columns are dynamic I am having an issue with defining them there.
On top of that, I am unable to pick out the values for the date besides brute forcing through the values and storing all the unique date entries as columns. And if I have them, then how do I match them up with the correct data entry to display the correct value in the grid?
You could use the kendo ui PivotGrid component. It is built for dealing with categorical data. However, you probably would find that takes up to much real estate.
That leaves the task of manually pivoting the data yourself. A task that is relatively simple if you make the assumptions that the Date values over all the data never have a month from two different years (If there was a 01-01-2018 and 01-01-2017 they are both Jan) and the is only one row for each date/name combo. (If there were two values for a date/name you would have to decide what is done with the value? min, max, first, last, mean ?)
data =
[
{ Date: '01-01-2018', Name: 'Foo', Value: 1000},
{ Date: '02-01-2018', Name: 'Foo', Value: 2000},
{ Date: '03-01-2018', Name: 'Foo', Value: 3000},
{ Date: '01-01-2018', Name: 'Bar', Value: 1400},
{ Date: '02-01-2018', Name: 'Bar', Value: 2000},
{ Date: '03-01-2018', Name: 'Bar', Value: 5000}
];
// distinct month nums over all data
months = [];
data.forEach(function(item) {
var parts = item.Date.split('-');
var month = parts[0] - 1;
if (months.indexOf(month) == -1) months.push(month);
});
// sort and convert month num to month name (for columns)
months.sort();
months.forEach(function(monthNum,index,arr) {
arr[index] = new Date(2018,monthNum,1).toLocaleString("en-US", { month: "short" });
});
function mmddyyyyToMon(mmddyyyy) {
var parts = mmddyyyy.split("-");
var jsMonth = parts[0] - 1;
var jsDay = parts[1];
var jsYear = parts[2];
return new Date(jsYear,jsMonth,jsDay).toLocaleString("en-US", { month: "short" });
}
// helper to make sure pivot item has one field for every month observed over all data
function newPivotItem () {
var result = { Name: '' };
months.forEach(function(month) {
result[month] = undefined;
})
return result;
}
// presume data grouped by Name and ordered by month within
var pivotData = [];
var pivotItem = {};
data.forEach (function (item) {
var parts = item.Date.split("-");
var jsMonth = parts[0] - 1;
var jsDay = parts[1];
var jsYear = parts[2];
var month = new Date(jsYear,jsMonth,jsDay).toLocaleString("en-US", { month: "short" });
if (pivotItem.Name != item.Name) {
// start next group of data for a name
pivotItem = newPivotItem();
pivotData.push(pivotItem);
pivotItem.Name = item.Name;
}
// set value for month for the name
pivotItem[month] = item.Value;
})
console.log (pivotData);
I hope this helps you.
I made a dojo for you and pasted the code bellow for the future.
I used the possibility of having a callback transport for the read.
https://dojo.telerik.com/imeNOdUh/2
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.common.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.default.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.mobile.all.min.css">
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.1.221/js/angular.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.1.221/js/jszip.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.1.221/js/kendo.all.min.js"></script></head>
<body>
<div id="my-grid"></div>
<script>
function fetchData(success, fail) {
success([
{ Date: '01-01-2018', Name: 'Foo', Value: 1000},
{ Date: '02-01-2018', Name: 'Foo', Value: 2000},
{ Date: '03-01-2018', Name: 'Foo', Value: 3000},
{ Date: '01-01-2018', Name: 'Bar', Value: 1400},
{ Date: '02-01-2018', Name: 'Bar', Value: 2000},
{ Date: '03-01-2018', Name: 'Bar', Value: 5000}
]);
}
var $gridElement = $('#my-grid');
$gridElement.kendoGrid({
dataSource: {
transport: {
read: function(options) {
fetchData(function(data) {
// get month names
var monthNames = data
.map(function(t) {
var monthName = kendo.format("{0:MMM}", kendo.parseDate(t.Date, 'MM-dd-yyyy'));
return monthName;
})
.reduce(function(p, t) {
if (p.indexOf(t) == -1)
p.push(t);
return p;
}, []);
// transform
var result = data.reduce(function(p, t) {
var monthName = kendo.format("{0:MMM}", kendo.parseDate(t.Date, 'MM-dd-yyyy'));
var existing = p.filter(function(t2) {
return t2.Name == t.Name;
});
if (existing.length) {
existing[0][monthName] = t.Value;
} else {
var n = {
Name: t.Name
};
monthNames.forEach(function(m) {
n[m] = 0;
});
n[monthName] = t.Value;
p.push(n);
}
return p;
}, []);
options.success(result);
});
}
}
}
});
</script>
</body>
</html>
class item {
name: string;
order: number;
}
let onUp = new Rx.Subject<item>();
let list = new Rx.BehaviorSubject<item>([
{ name: "7", order: 70 },
{ name: "2", order: 20 },
{ name: "5", order: 50 },
{ name: "3", order: 30 },
{ name: "4", order: 40 },
{ name: "6", order: 60 },
{ name: "1", order: 10 }
]);
list.subscribe(console.log);
onUp.subscribe(anItem => {
let numberList: item[];
list
.take(1)
.map(x => x.sort((a, b) => a.order - b.order))
.subscribe(ddList => (numberList = ddList));
let index = numberList.indexOf(numberList.find(num => num.order == anItem));
let ddvalue = numberList[index];
let preddvalue = numberList[index - 1];
let preddvalueOrder = preddvalue.order;
preddvalue.order = ddvalue.order;
ddvalue.order = preddvalue.order;
list.next(numberList);
});
onUp.next(30);
whats the reactive way to exchange values of "order" with another object from the list?
I have a bunch of items that I should be able to reorder.
The order of an item is based on the order property of the item object in the item list.
I reorder the items by switching the order property of two items.
In the sample code, the onUp Subject, emits an orderNumber which should be switched with the upper item(ordered by order property)
The sample code works, its just that its probably bad practice since the second subscribe is asynchronous.
An alternative is to do the reordering inside the subscription inside the outer subscription but that's also bad practice(not sure why aside from the fact that its a messy nest).
I always see flatMap but if I understand correctly the 2nd subscription just uses a data from the first subscription to get a data.
In this case I need both data from the first and second subject to get the two items to switch and the new list to push to list subject.
Ah.... Is maintaining 2 lists ok to you? One is the unsorted, the other one always listen to unsorted changes and sort it.
const list = new Rx.BehaviorSubject([
{ name: "7", order: 70 },
{ name: "2", order: 20 },
{ name: "5", order: 50 },
{ name: "3", order: 30 },
{ name: "4", order: 40 },
{ name: "6", order: 60 },
{ name: "1", order: 10 }
]);
const sortedList = new Rx.BehaviorSubject([]);
const onUp = new Rx.BehaviorSubject(0);
list
.map(x => x.sort((a, b) => a.order - b.order))
.subscribe(x => sortedList.next(x));
sortedList.subscribe(console.log);
onUp.subscribe(x => {
const idx = sortedList.getValue()
.findIndex(itm => itm.order === x);
if (idx < 1) return;
const list = sortedList.getValue();
const prev = list[idx - 1].order;
const curr = list[idx].order;
list[idx].order = prev;
list[idx - 1].order = curr;
sortedList.next(list);
});
onUp.next(30);
onUp.next(70);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
getValue() of BehaviorSubject is bad practice as well(says so in my source by Ben Lesh). readup on withLatestFrom or combineLatest for combining two observables.
class item {
name: string;
order: number;
}
let onUp = new Rx.Subject<item>();
let list = new Rx.BehaviorSubject<item[]>([
{ name: "7", order: 70 },
{ name: "2", order: 20 },
{ name: "5", order: 50 },
{ name: "3", order: 30 },
{ name: "4", order: 40 },
{ name: "6", order: 60 },
{ name: "1", order: 10 }
]);
list.subscribe(console.log);
// onUp.subscribe(anItem => {
onUp
.withLatestFrom(list, (item, itemList) => {
return { item: item, itemList: itemList };
})
.subscribe(itemWithList => {
let numberList: item[] = itemWithList.itemList.sort(
(a, b) => a.order - b.order
);
let orderToUp: number = itemWithList.item;
let index = numberList.findIndex(x => x.order === orderToUp);
let ddvalue = numberList[index];
let preddvalue = numberList[index - 1];
console.log(ddvalue);
let preddvalueOrder = preddvalue.order;
preddvalue.order = ddvalue.order;
ddvalue.order = preddvalueOrder;
list.next(numberList);
});
onUp.next(30);
Paste it here:
https://emeraldwalk.github.io/rxjs-playground/#
Source:
https://stackoverflow.com/a/45227115
I need to get only last week posts. I don't find examples in Documentation and for tests I use Query-Engine demo with this code:
models = [
title: 'WRONG: Future'
date: new Date("2015-05-23")
,
title: 'Correct 1'
date: new Date("2015-05-22")
,
title: 'Correct 2'
date: new Date("2015-05-20")
,
title: 'WRONG: Old'
date: new Date("2015-05-15")
]
max_date = min_date = new Date("2015-05-22");
min_date.setDate(min_date.getDate() - 7);
result = queryEngine.createCollection(models)
.findAll({
$and: {
date: {
$lte: max_date
},
date: {
$gt: min_date
}
}
}).toJSON()
return result
How to get posts in this slice?
here is the right answer:
models = [
title: 'WRONG: Future'
date: new Date("2015-05-23")
,
title: 'Correct 1'
date: new Date("2015-05-22")
,
title: 'Correct 2'
date: new Date("2015-05-20")
,
title: 'WRONG: Old'
date: new Date("2015-05-15")
]
max_date = new Date("2015-05-22");
min_date = new Date(max_date.getTime() - 7*24*60*60*1000);
result = queryEngine.createCollection(models)
.findAll({
date: {$lte: max_date, $gt: min_date }
}).toJSON()
return result
Im having an issue doing something thats probably pretty simple.
My LINQ query is returning a result set of 10 objects.
Something like:
Name: Bill, Action: aaa, Id: 832758
Name: Tony, Action: aaa, Id: 82fd58
Name: Bill, Action: bbb, Id: 532758
Name: Tony, Action: bbb, Id: 42fd58
What I need to do, is to group these so that there are only 2 rows, ie one per Name, but have the ones with "Action: bbb" move into a different column. So the output would be:
Name: Bill, Action: aaa, Action_2: bbb, Id: 832758, Id_2: 532758
Name: Tony, Action: aaa, Action_2: bbb, Id: 82fd58, Id_2: 42fd58
Can anyone explain to me how I might do that?
Cheers
var myData = new []
{
new { Name = "Bill", Action="aaa", Id = "832758" },
new { Name = "Tony", Action="aaa", Id = "82fd58" },
new { Name = "Bill", Action="bbb", Id = "532758" },
new { Name = "Tony", Action="bbb", Id = "42fd58" }
};
var result = myData
.GroupBy(x=>x.Name)
.Select(g=>new
{
Name = g.Key,
Action = g.First().Action,
Action_2 = g.Last().Action,
Id = g.First().Id,
Id_2 = g.Last().Id
});
The query above assumes that you have only two rows for each name; if you have multiple rows per name, you can take the second Action/Id value by using .Skip(1).Take(1) instead of .Last()
I don't think there's a real simple way to do it. I've connocted this, though, which might get you started:
var myData = new []
{
new { Name = "Bill", Action="aaa", Id = "832758" },
new { Name = "Tony", Action="aaa", Id = "82fd58" },
new { Name = "Bill", Action="bbb", Id = "532758" },
new { Name = "Tony", Action="bbb", Id = "42fd58" }
};
// group all the Names together
var result = from m in myData
group m by m.Name into names
orderby names.Key
select names;
// go through each Name group and create the output string to store in sbLines
var sbLines = new StringBuilder();
foreach (var name in result)
{
var sb = new StringBuilder();
sb.AppendFormat("Name: {0}, ", name.Key);
int count = 1;
foreach (var item in name)
{
if(count > 1)
sb.AppendFormat("Action_{0}: {1}, ", count, item.Action);
else
sb.AppendFormat("Action: {0}, ", item.Action);
count++;
}
count = 1;
foreach (var item in name)
{
if(count > 1)
sb.AppendFormat("Id_{0}: {1}, ", count, item.Id);
else
sb.AppendFormat("Id: {0}, ", item.Id);
count++;
}
sbLines.Append(sb.ToString().Trim(new char[] { ' ',',' }));
sbLines.Append(Environment.NewLine);
}
Console.WriteLine(sbLines.ToString());
Run it here: http://ideone.com/8UTxr