I have a following set of numbers:
1 137
1 143
11 37
11 46
11 132
46 65
46 139
69 90
Now, I need to group the data by the first value in a way that no group key is present in the group values. So, for instance, if I were to simply group data, I'd get this result:
1 137
143
11 37
46
132
46 65
139
69 90
46 here is a group key in the third group and a group value in the second group. In this case I need to merge the group values of the third group into a second group and remove the third group.
The end result of the grouping should look like this:
1 137
143
11 37
46
132
65
139
69 90
I'm relatively new to C#, so I was wondering if there's a fancy way to do it using LINQ.
Try this LINQ solution:
var numbers = new List<Number>
{
new Number {X = 1, Y = 137},
new Number {X = 1, Y = 143},
new Number {X = 11, Y = 37},
new Number {X = 11, Y = 46},
new Number {X = 11, Y = 132},
new Number {X = 46, Y = 65},
new Number {X = 46, Y = 139},
new Number {X = 69, Y = 90}
};
var result = numbers.GroupBy(c => c.X);
var result2 = numbers.FirstOrDefault(c => result.Select(d => d.Key).Contains(c.Y));
var finalResult = numbers.Where(x => x.X == result2?.Y)
.Select(x => { x.X = result2.X;x.Y = x.Y; return x; } )
.Union(numbers.Where(c => c.X != result2?.Y)).GroupBy(c => c.X ,
(key, element) => new
{
Key = key,
Element = element.Select(c => c.Y).ToList()
});
The result:
This could work for you
public static List<Numbers> setNumbers()
{
List<Numbers> num = new List<Numbers>();
num.Add(new Numbers() { Column1 = 1, Column2 = 137 });
num.Add(new Numbers() { Column1 = 1, Column2 = 143 });
num.Add(new Numbers() { Column1 = 11, Column2 = 37 });
num.Add(new Numbers() { Column1 = 11, Column2 = 46 });
num.Add(new Numbers() { Column1 = 11, Column2 = 132 });
num.Add(new Numbers() { Column1 = 46, Column2 = 65 });
num.Add(new Numbers() { Column1 = 46, Column2 = 139 });
num.Add(new Numbers() { Column1 = 69, Column2 = 90 });
return num;
}
public static void group()
{
List<Numbers> numbers = setNumbers();
var grouppedNumbers = numbers
.GroupBy(x => x.Column1).ToList();
grouppedNumbers.AddRange(grouppedNumbers.FirstOrDefault(x => x.First().Column1.Equals(46)).Select(s => new Numbers() { Column1 = 11, Column2 = s.Column2 }).GroupBy(g => g.Column1).ToList());
grouppedNumbers.Remove(grouppedNumbers.FirstOrDefault(x => x.First().Column1.Equals(46)));
foreach (var groups in grouppedNumbers)
{
Console.WriteLine(groups.First().Column1);
foreach(var i in groups)
{
Console.WriteLine(i.Column1+" "+ i.Column2);
}
}
}
SQL
select * from tempFinal where TypeId not in (13,14,15,51,52,55,59) -- Note: From Stored
Current LINQ
int LeaveExists = (from dt in db.LeaveDetails join
leavH in db.LeaveHeaders on dt.LeaveHeaderId equals leavH.LeaveHeaderId
where (leavH.LeaveTypeId != 55 && leavH.LeaveTypeId != 59 && . . . . )
&& dt.TestId == Id
select dt).Count();
I saw this LINK and test the code.
int[] tempNotIn = new int[] { 13, 14, 15, 51, 52, 55, 59 };
int LeaveExists = (from dt in db.LeaveDetails join
leavH in db.LeaveHeaders on dt.LeaveHeaderId equals leavH.LeaveHeaderId
where !tempNotIn.Contains((int)leavH.LeaveTypeId) &&
dt.TestId == Id
select dt).Count();
it gives me an error The name LeavH does not exist in the current context.
TestId is INT
To all who view my post I got it. After a while of Trial and came up to this query and it's working
int[] tempNotIn = new int[] { 13, 14, 15, 51, 52, 55, 59 };
var LeaveExists = (from dt in db.LeaveDetails join
leavH in db.LeaveHeaders on dt.LeaveHeaderId equals leavH.LeaveHeaderId
where !tempNotIn.Contains((int)leavH.LeaveTypeId) &&
dt.TestId == Id
select dt).Count();
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am getting some hierarchical data in flat format from SQL server. This is how the data looks.
Group Name Level Parent Value1 Value2 RowID
Global Product1 1 10 20 1
APAC Product1 1 80 90 2
EMEA Product1 1 50 70 3
Global Product2 2 Product1 100 200 4
APAC Product2 2 Product1 800 900 5
EMEA Product2 2 Product1 500 700 6
Global Product3 3 Product2 10 20 7
APAC Product3 3 Product2 80 90 8
Global Product4 4 Product3 110 120 9
APAC Product4 4 Product3 810 190 10
EMEA Product4 4 Product3 510 170 11
.....
.....
Global Product12 1 10 20 100
I need to group the data based on Name and Level columns. Then I need to create multiple keys based on combination of Group Column & Value1 & Value2 columns. See the below JSON output to get more idea about the output. Please keep in mind number of Group can change.
[
{
Id: 1,
Name: Product1,
parentId: null,
GlobalValue1: 10,
GlobalValue2: 20,
APACValue1: 80,
APACValue2: 90,
EMEAValue1: 50,
EMEAValue2: 70
},
{
Id: 2,
Name: Product2,
parentId: 1,
GlobalValue1: 100,
GlobalValue2: 200,
APACValue1: 800,
APACValue2: 900,
EMEAValue1: 500,
EMEAValue2: 700
},
{
Id: 3,
Name: Product3,
parentId: 2,
GlobalValue1: 10,
GlobalValue2: 20,
APACValue1: 80,
APACValue2: 90,
EMEAValue1: null,
EMEAValue2: null
},
{
Id: 4,
Name: Product4,
parentId: 3,
GlobalValue1: 110,
GlobalValue2: 120,
APACValue1: 810,
APACValue2: 190,
EMEAValue1: 510,
EMEAValue2: 170
}{
Id: 122,
Name: Product12,
parentId: null3,
GlobalValue1: 10,
GlobalValue2: 20,
APACValue1: null,
APACValue2: null,
EMEAValue1: null,
EMEAValue2: null
}
]
I need to auto generate ID field. This field will be use to establish parent-child relationship. I cannot rely onnamecolumn as it can repeat (can have same value) across different levels.. There will be more than 1 product and each level. In my example, I am just showing one product per level just to keep example simple.
Here is a bit of code that does what I think you want. It's a console application and I used Newtonsoft.Json (get it with NuGet in references) to create the JSON.
class Program
{
static void Main(string[] args)
{
var data = initData();
var result = getGroupedData(data);
var json = new Newtonsoft.Json.JsonSerializer
{
Formatting=Formatting.Indented
};
json.Serialize(Console.Out,result);
Console.ReadKey();
}
private static object getGroupedData(DataTable dt)
{
var id = 1;
var rows = dt.Rows.OfType<DataRow>(); //because for some reason DataRowCollection is not an IEnumerable<DataRow>
var products = rows //the products, each defined by Name and Level
.GroupBy(r => new { Name = r.Field<string>("Name"), Level = r.Field<int>("Level") })
.Select(g => new
{
Id = id++, //create the id
Name = g.Key.Name,
Level = g.Key.Level,
// select the parent and throw exception if there are more or less than one
Parent = g.Select(r => r.Field<string>("Parent")).Distinct().Single()
}).ToList();
var results = products
.Select(p => new //need a partial result first, containing the Global, Apac and Emea rows, if they exist
{
Id = p.Id,
Name = p.Name,
// Assuming the Level of a child is Level of parent+1
Parent = products.FirstOrDefault(par => par.Name == p.Parent && par.Level + 1 == p.Level),
Global = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "Global"),
Apac = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "APAC"),
Emea = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "EMEA")
})
.Select(x => new //create the final result
{
Id = x.Id,
Name = x.Name,
ParentId = x.Parent==null? (int?)null :x.Parent.Id,
GlobalValue1 = x.Global == null ? (double?)null : x.Global.Field<double?>("Value1"),
GlobalValue2 = x.Global == null ? (double?)null : x.Global.Field<double?>("Value2"),
APACValue1 = x.Apac == null ? (double?)null : x.Apac.Field<double?>("Value1"),
APACValue2 = x.Apac == null ? (double?)null : x.Apac.Field<double?>("Value2"),
EMEAValue1 = x.Emea == null ? (double?)null : x.Emea.Field<double?>("Value1"),
EMEAValue2 = x.Emea == null ? (double?)null : x.Emea.Field<double?>("Value2")
})
.ToArray();
return results;
}
private static DataTable initData()
{
var dt = new DataTable();
dt.Columns.Add("Group", typeof(string));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Level", typeof(int));
dt.Columns.Add("Parent", typeof(string));
dt.Columns.Add("Value1", typeof(double));
dt.Columns.Add("Value2", typeof(double));
dt.Columns.Add("RowID", typeof(int));
dt.Rows.Add("Global", "Product1", 1, null, 10, 20, 1);
dt.Rows.Add("APAC", "Product1", 1, null, 80, 90, 2);
dt.Rows.Add("EMEA", "Product1", 1, null, 50, 70, 3);
dt.Rows.Add("Global", "Product2", 2, "Product1", 100, 200, 1);
dt.Rows.Add("APAC", "Product2", 2, "Product1", 800, 900, 2);
dt.Rows.Add("EMEA", "Product2", 2, "Product1", 500, 700, 3);
dt.Rows.Add("Global", "Product3", 3, "Product2", 10, 20, 1);
dt.Rows.Add("APAC", "Product3", 3, "Product2", 80, 90, 2);
dt.Rows.Add("Global", "Product4", 4, "Product3", 110, 120, 1);
dt.Rows.Add("APAC", "Product4", 4, "Product3", 810, 190, 2);
dt.Rows.Add("EMEA", "Product4", 4, "Product3", 510, 170, 3);
return dt;
}
}
With POCO object, the method would look like this:
private static object getGroupedData(IEnumerable<MyPoco> rows)
{
var id = 1;
var products = rows //the products, each defined by Name and Level
.GroupBy(r => new { Name = r.Name, Level = r.Level })
.Select(g => new
{
Id = id++, //create the id
Name = g.Key.Name,
Level = g.Key.Level,
// select the parent and throw exception if there are more or less than one
Parent = g.Select(r => r.Parent).Distinct().Single()
}).ToList();
var results = products
.Select(p => new //need a partial result first, containing the Global, Apac and Emea rows, if they exist
{
Id = p.Id,
Name = p.Name,
// Assuming the Level of a child is Level of parent+1
Parent = products.FirstOrDefault(par => par.Name == p.Parent && par.Level + 1 == p.Level),
Global = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "Global"),
Apac = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "APAC"),
Emea = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "EMEA")
})
.Select(x => new //create the final result
{
Id = x.Id,
Name = x.Name,
ParentId = x.Parent==null? (int?)null :x.Parent.Id,
GlobalValue1 = x.Global == null ? (double?)null : x.Global.Value1,
GlobalValue2 = x.Global == null ? (double?)null : x.Global.Value2,
APACValue1 = x.Apac == null ? (double?)null : x.Apac.Value1,
APACValue2 = x.Apac == null ? (double?)null : x.Apac.Value2,
EMEAValue1 = x.Emea == null ? (double?)null : x.Emea.Value1,
EMEAValue2 = x.Emea == null ? (double?)null : x.Emea.Value2
})
.ToArray();
return results;
}
How can order my list using Linq equals rank() over in SQL ?
For example rank is my List<Player>
class Player
{
public int Id;
public int RankNumber;
public int Points;
public int Name;
}
Original Rank list:
RankNumber Points Name Id
1 100 James 01
2 80 Mike 50
3 80 Jess 22
4 50 Jack 11
5 50 Paul 03
6 10 Monik 13
I need this Rank:
RankNumber Points Name Id
1 100 James 01
2 80 Mike 50
2 80 Jess 22
4 50 Jack 11
4 50 Paul 03
6 10 Monik 13
I don't think there is a good way to convert this directly to Linq to SQL but you could do this:
var rankedPlayers = players
.OrderByDescending(p => p.Points)
.Select((p, r) => new Player
{
Id = p.Id,
RankNumber = players.Where(pl => pl.Points > p.Points).Count() + 1,
Points = p.Points,
Name = p.Name
});
It gives you the correct output but will convert horribly and inefficiently to SQL. So I would suggest this modification which materialises the data to a list before creating the ranks:
var rankedPlayers = players
.OrderByDescending(p => p.Points)
.ToList() //<--- Add this
.Select((p, r) => new Player
{
Id = p.Id,
RankNumber = players.Where(pl => pl.Points > p.Points).Count() + 1,
Points = p.Points,
Name = p.Name
});
You can try below expression:
var newData = players
.OrderByDescending(x => x.Points)
.GroupBy(x => x.Points)
.SelectMany((x, index) => x.Select(y => new Player
{
Name = y.Name,
Points = y.Points,
RankNumber = index + 1,
Id = y.Id
}));
players contains IEnumerable of objects of type Player and newData contains ordered data with rank.
I have following Table with records for ActivityLog:
ID, UserId, Category, Created
1 11 DeAssigned 05/10/2012
2 11 LogIn 05/11/2012
3 20 Assigned 06/15/2012
4 11 Assigned 06/10/2012
5 20 DeAssigned 06/13/2012
6 20 Assigned 07/12/2012
7 11 DeAssigned 07/16/2012
8 20 Assigned 08/15/2012
...
now i want to query the Table to create same struct the same Result such as this:
var data = new[] {
new { Month = "05", Assigned = 14, DeAssigned = 5, LogIn=1 },
new { Month = "06", Assigned = 5, DeAssigned = 2, LogIn=0 },
new { Month = "07", Assigned = 50, DeAssigned = 8, LogIn=0 },
new { Month = "08", Assigned = 15, DeAssigned = 1, LogIn=0 }
};
what i have achieved:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by new { l.Created.Value.Month, l.Category }
into groups
orderby groups.Key.Month
select new
{
Month = groups.Key.Month,
Category = groups.Key.Category,
Count = groups.Count()
});
there is not optimal result but count all Activity's grouped by Month:
[0] {Month = 6, Category = Assigned, Count = 2}
[0] {Month = 6, Category = Designed, Count = 1}
[0] {Month = 6, Category = LogIn, Count = 1}
[0] {Month = 7, Category = Assigned, Count = 3}
How can i query my Table to Format my Result in "Horizontal Counted" format?
Or simplier:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by l.Created.Month into groups
orderby groups.Key ascending
select new
{
Month = groups.Key,
Assigned = groups.Where(g => g.Category == "Assigned").Count(),
Deassigned = groups.Where(g => g.Category == "DeAssigned").Count(),
LogIn = groups.Where(g => g.Category == "LogIn").Count()
});