Dictionary shoppingList = new Dictionary <string, int>()
{
{"Eggs",200 },
{"Milk",200},
{"Fish",400},
{"Apples",150}
};
Dictionary does not have a concept of "first", and indeed is free to re-order things. Now you can get a .First() item, but it's only guaranteed for that enumeration, and the order might not be the order you expect or want. That said, I'm not aware of a specific case .Net will actually do this; just be aware it's not part of the "contract" for the type.
Really, it seems like what you have here is more of a List<ShoppingItem> (it's even in the name of the variable!), where ShoppingItem is a class with properties for Name and Price.
To be more predictable about retrieving the first item, it might be helpful to create a class called ShoppingItem and then use a List instead of a Dictionary:
public class ShoppingItem
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Create a List using your new ShoppingItem type.
List<ShoppingItem> shoppingList = new List<ShoppingItem>();
Populate your list:
shoppingList.Add(
new ShoppingItem
{
Id = 1,
Name = "Eggs",
Price = 200
});
shoppingList.Add(
new ShoppingItem
{
Id = 2,
Name = "Applies",
Price = 150
});
Then, finding the first in the sequence can be achieved in a number of ways:
var firstUsingFirst = shoppingList.First();
var firstUsingIndex = shoppingList[0];
var firstLowestId = shoppingList.Find(item => item.Id == (shoppingList.Min(e => e.Id)));
Each method returns a ShoppingItem object, so get the values of the class properties like:
int firstId = firstUsingFirst.Id
Lots of examples in the documentation here.
Related
Scenario:
I have to export an excel file which will contain list of Parts. We have enabled the user to select the columns and get only selected columns' data in the exported file. Since this is a dynamic report, I am not using any concrete class to map the report as this will result in exporting empty column headers in the report, which is unnecessary. I am using Dynamic Linq to deal with this scenario.
I have a list of dynamic objects fetched from dynamic linq.
[
{"CleanPartNo":"Test","Description":"test","AliasPartNo":["258","145","2313","12322"]},
{"CleanPartNo":"Test1","Description":"test1","AliasPartNo":[]}
]
How can I get 4 rows out of this json like
Please note that I cannot use a strongly typed object to deserialize/ Map it using JSON.Net
Update
Following is the code:
public class Part
{
public int Id { get; set; }
public string CleanPartNo { get; set; }
public string Description { get; set; }
public List<PartAlias> AliasPartNo { get; set; }
}
public class PartAlias
{
public int PartId { get; set; }
public int PartAliasId { get; set; }
public string AliasPartNo { get; set; }
}
var aliases = new List<PartAlias> {
new PartAlias{AliasPartNo="258" },
new PartAlias{AliasPartNo="145" },
new PartAlias{AliasPartNo="2313" },
new PartAlias{AliasPartNo="12322" }
};
List<Part> results = new List<Part> {
new Part{CleanPartNo="Test", Description= "test", PartAlias=aliases },
new Part{CleanPartNo="Test1", Description= "test1" }
};
var filters = "CleanPartNo,Description, PartAlias.Select(AliasPartNo) as AliasPartNo";
var dynamicObject = JsonConvert.SerializeObject(results.AsQueryable().Select($"new ({filters})"));
in the dynamicObject variable I get the json mentioned above
Disclaimer: The following relies on anonymous classes, which is not exactly the same as dynamic LINQ (not at all), but I figured that it may help anyway, depending on your needs, hence I decided to post it.
To flatten your list, you could go with a nested Select, followed by a SelectMany (Disclaimer: This assumes that every part has at least one alias, see below for the full code)
var flattenedResult = result.Select(part => part.AliasPartNumber.Select(alias => new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
})
.SelectMany(part => part);
You are first projecting your items from result (outer Select). The projection projects each item to an IEnumerable of an anonymous type in which each item corresponds to an alias part number. Since the outer Select will yield an IEnumerable<IEnumerable> (or omething alike), we are using SelectMany to get a single IEnumerable of all the items from your nested IEnumerables. You can now serialize this IEnumerable of instances of an anonymous class with JsonConvert
var json = sonConvert.SerializeObject(flatResults);
Handling parts without aliases
If there are no aliases, the inner select will yield an empty IEnumerable, hence we will have to introduce a special case
var selector = (Part part) => part.AliasPartNumber?.Any() == true
? part.AliasPartNumber.Select(alias => new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
})
: new[]
{
new
{
CleanPartNo = part.CleanPartNo,
Description = part.Description,
AliasPartNo = alias.AliasPartNo
}
};
var flattenedResult = result.Select(selector).SelectMany(item => item);
From json you provided you can get values grouped by their name in this way:
var array = JArray.Parse(json);
var lookup = array.SelectMany(x => x.Children<JProperty>()).ToLookup(x => x.Name, x => x.Value);
then this is just a manner of simple loop over the lookup to fill the excel columns.
However, I would suggest to do the flatenning before JSON. I tried for some time to make it happen even without knowing the names of the columns that are arrays, but I failed, and since it's your job, I won't try anymore :P
I think the best way here would be to implement custom converter that would just multiply objects for properties that are arrays. If you do it well, you would get infinite levels completely for free.
I need to convert this DTO
public class MyDTO
{
[JsonProperty("studentInfo")]
public StudentInfo studentInfo {get; set; }
public class StudentInfo
{
[JsonProperty("others")]
public ICollection<AnotherDTO[]> Others { get; set; }
}
public class AnotherDTO
{
[JsonProperty("name")]
public string name { get; set; }
}
}
to this model
public class MyModel
{
public StudentInfo studentInfo {get; set; }
public class StudentInfo
{
public ICollection<Another[]> Others { get; set; }
}
public class Another
{
public string name { get; set; }
}
}
I am getting hung up on the ICollection. Here is the bit where I am trying to populate ICollection Others.
private static ICollection<MyModel.Another[]> getAnothers(MyDTO myDTO, MyModel myModel)
{
List<MyModel.Another> myList = new List<MyModel.Another>();
foreach(var x in myDTO.studentInfo.Others)
{
foreach(var y in x)
{
myList.Add(new MyModel.Another
{
name = y.name
});
}
}
}
MyModel.Another[] newList;
newList = myList.ToArray();
ICollection<MyDTO.AnotherDTO[]> ic = (ICollection<MyModel.Another[]>newList.Cast<MyModel.Another[]>().ToList();
This last line is giving me the following error:
Unable to cast object of type MyModel to type MyModel[].
I would appreciate any help.
Instead of manually mapping the object, I would suggest to use AutoMapper. AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. You can also get Nuget package for AutoMapper
Just define the mapping for the objects -
Mapper.CreateMap<MyDTO, MyModel>();
..and simply map the object like this -
var myModelObject = Mapper.Map<MyModel>(myDtoObject);
Please refer this getting started link.
You can use a select statement to convert the collection.
var myDto = new MyDto
{
studentInfo = new MyModel.StudentInfo
{
Others = new List<AnotherDTO[]>
{
new[]
{
new AnotherDTO { Name = "a" },
new AnotherDTO { Name = "b" }
},
new[]
{
new AnotherDTO { Name = "x" },
new AnotherDTO { Name = "y" }
}
}
}
var model = new MyModel
{
studentInfo = new MyModel.StudentInfo
{
Others = dto.StudentInfo.Others
.Select(otherDtoArray =>
otherDtoArray
.Select(otherDto => new MyModel.Other {Name = otherDto.Name})).ToList()
}
Thanks for your comments everyone. My main problem was trying to convert the ICollection.
I ended up changing ICollection in my model to simply List. And it is working out nicely. I am not able to Use AutoMapper as was suggested, but I do see the value of it for case like mine.
There's all kinds of wrong in your code.
foreach(var x in myDTO.studentInfo.Others)
{
foreach(var y in x)
{
myList.Add(new MyModel.Another
{
name = y.name
});
}
Why do you need the 2nd foreach loop ? Your first foreach loop is already looping through your Others (type: ICollection). Each "x" is an instance of AnotherDTO.
Secondly, the following is completely wrong:
MyModel.Another[] newList;
newList = myList.ToArray();
ICollection<MyDTO.AnotherDTO[]> ic = (ICollection<MyModel.Another[]>newList.Cast<MyModel.Another[]>().ToList();
MyList is already a list. You're then trying to cast it as an Array and then back to a list. There's no point in doing this.
Also, you might as well just not use ICollection at all. It's heavy for nothing. Just use List.
Also don't name variables with simple letters 'a', 'b', 'x', 'y', etc... You're going to get flamed by your colleagues once you're on the job market.
Here's the corrected version of your code:
public class SomeClass
{
public static List<Another> MapAnotherDtoToAnother(List<AnotherDTO> others)
{
List<Another> anotherList = new List<Another>();
foreach(var anotherDto in others)
{
Another another = new Another();
/* Populate fields of `another` whatever they are from `anotherDto` */
another.FirstName = anotherDto.FirstName;
anotherList.Add(another);
}
return anotherList;
}
}
To convert an ICollection to List just do:
/* Convert your ICollection to a List */
List<AnotherDTO> AnotherDTOList = myDto.StudentInfo.Others.Cast<AnotherDTO>().ToList()
/* Use your static function get your non-dto counterpart */
List<Another> anothers = SomeClass.MapAnotherDtoToAnother(AnotherDTOList);
Hope it helps.
Good luck!
I am using generic method to fill my dropdown for all types
below is my code.
the entity type are as follow
public class Role
{
public string Id { get; set; }
public string Name { get; set; }
}
public class DropDown
{
public string Id { get; set; }
public string Name { get; set; }
}
i am able to fetch data successfully at
var data = DataFetcher.FetchData<T>();
private static void Main( string[] args )
{
List<DropDown> cities = BLL.GetDataList<City>();
List<DropDown> states = BLL.GetDataList<State>();
List<DropDown> roles = BLL.GetDataList<Role>();
}
public static class BLL
{
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data as List<DropDown>;
}
}
I knew this cast data as List<DropDown> will fail,thats why its returning null back to calling method,
How can i cast Generic list to List of Known Type?
You have to ask yourself: how do I want to convert T to DropDown? If you can't answer this, the answer is: you can't.
I guess your DropDown class has an object Value property, that holds the dropdown value, and you wish to assign the data entity to that property.
Then you can project the list of data entities to DropDowns as such:
var data = DataFetcher.FetchData<T>();
return data.Select(d => new DropDown { Value = d }).ToList();
As for your edit: so you have at least one type, the displayed Role, that has an Id and Name property. But type T doesn't guarantee this, so you'd need to introduce an interface:
public interface INamedIdentifyableEntity
{
string Id { get; set; }
string Name { get; set; }
}
And apply this to your entities. Then introduce it as a generic constraint and do the mapping:
return data.Select(d => new DropDown
{
Id = d.Id,
Name = d.Name,
}).ToList();
But you don't want this, as here you are tying these two properties to dropdowns. Tomorrow you'll want an entity with Code instead of Id and Text instead of Name, so you'll have to add more interfaces, more overloads, and so on.
Instead you might want to use reflection, where you can specify the member names in the call:
List<DropDown> cities = BLL.GetDataList<City>(valueMember: c => c.CityCode, displayMember: c => c.FullCityname);
And use these member expressions to look up data's values and fill those into the DropDown.
However, you're then reinventing the wheel. Leave out your DropDown class entirely, and leave the dropdown generation to the front end, in this case MVC:
var cities = DataFetcher.FetchData<City>();
var selectList = new SelectList(cities.Select(c => new SelectListItem
{
Selected = (c.Id == selectedCityId),
Text = c.FullCityName,
Value = c.CityCode,
});
Or:
var selectList = new SelectList(cities, "CityCode" , "FullCityName", selectedCityId);
One solution is to use AutoMapper.
First create a map between your models like this:
AutoMapper.Mapper.CreateMap<Role, DropDown>();
Do the same thing for City and State classes if you need to.
Then you can use AutpMapper to convert your objects to DropDown like this:
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data.Select(x => AutoMapper.Mapper.Map<DropDown>(x)).ToList();
}
If I understood the question correctly, you could use Linq as follows.
return data.Cast<DropDown>().ToList();
I have been trying to create a program that allows the user to edit things such as the supply of mp3 players which have a base value stored in the program:
public struct MP3_Players
{
public int ID { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public int MBsize { get; set; }
public decimal Price { get; set; }
public int Supply { get; set; }
}
MP3_Players player1 = new MP3_Players
{
ID = 1,
Make = "GET Technologies .inc",
Model = "HF 410",
MBsize = 4096,
Price = 129.95m,
Supply = 500
};
MP3_Players player2 = new MP3_Players
{
ID = 2,
Make = "Microsoft",
Model = "SOFT1",
MBsize = 1028,
Price = 432.99m,
Supply = 500
};
MP3_Players player3 = new MP3_Players
{
ID = 3,
Make = "PEAR",
Model = "APPLE3",
MBsize = 2056,
Price = 130.00m,
Supply = 500
};
MP3_Players player4 = new MP3_Players
{
ID = 4,
Make = "logitech",
Model = "DEF0",
MBsize = 2056,
Price = 53.35m,
Supply = 500
};
MP3_Players player5 = new MP3_Players
{
ID = 5,
Make = "Sennheiser",
Model = "HEIS1",
MBsize = 2056,
Price = 399.95m,
Supply = 500
};
Now making a method with a list isn't really an issue, I imagine it goes as follows:
public static void mutate()
{
List<MP3_Players> PlayerList = new List<MP3_Players>;
Playerlist.Add(player1);
Playerlist.Add(player2);
Playerlist.Add(player3);
Playerlist.Add(player4);
Playerlist.Add(player5);
}
My first question is simply a matter of improvement of code, but I suppose many people reading this will understand the problems I'm running into, primarily that player1 is not static, does this mean I will have to individually make every player static or is there an easier way?
The primary issue however lies with my attempts to create a small program to change the Supply, The idea is for a user to enter an ID and then allow them to edit the supply, this went well for me when I was using an array but I am having issues understanding how to use data in a list<> and change it(basically trying to reach the values stored in the list from other methods if possible at all).
An easier way would be to initialize the list by
List<MP3_Players> PlayerList = new MP3Players[]{
new MP3_Players()
{
ID = 1,
Make = "GET Technologies .inc",
Model = "HF 410",
MBsize = 4096,
Price = 129.95m,
Supply = 500
}, <-- include more instances of MP3_Players here
}.ToList();
and furthermore, the indexer [] can be used to access the elements in a list very similar to an array.
To solve your "list problem" you could use classes and a dictionary:
public class MP3_Players
{
/* ... */
}
public static void mutate()
{
var PlayerList = new Dictionary<int, MP3_Players>;
PlayerList.Add(player1.ID, player1);
PlayerList.Add(player2.ID, player2);
PlayerList.Add(player3.ID, player3);
PlayerList.Add(player4.ID, player4);
PlayerList.Add(player5.ID, player5);
}
Then you can access them via their ID and change them:
var player = PlayerList[ID];
player.Supply--;
player.Price -= 10;
BUT to solve your bigger problem of "persistency" you should think of a "data-store" to persist you data, e.g. Entity Framework and a DB.
Have you considered using collection initializer for inlining the creation of the PlayerList?
Where static is concerned, static method cannot access non static instance members.
One way is to create dictionary like other user explain if the ID of the players are Unique, if they are not doesn't start this approach. This is requirement of dictionary !
The other way using List.
List<MP3_Players> newList = PlayerList.FindAll(x=>x.Model == Apple3);
newList.ToList().ForEach(x => x.Storage = 30);
This will return every Player with Model Apple3 and second row will change all the values for Storage.
In C#, Structs are Immutable. This means that they can't be edited. If you wish to make a change to an item, then it needs to be replaced by a totally new item. You can avoid this by using a class.
One problem that I have ran into editing collections in an enumeration is that the collection was modified and the enumeration can no longer continue. This was happening because I was using a foreach loop that evaluates each item in the collection. I avoided it by using for loops and fetching the element from the list using its index and performing my edit there.
I am new to C# and find myself in situations sometimes where I have to return complex return types for some functions. Like the function may take in some object and return a different view of that object: some fields added, some removed, etc. And other times, I may take in a list of objects and want to return a list of some modified objects and possibly some aggregate calculations on all of them together.
I could accomplish these kinds of things by returning C# native types (like object[]), but it gets ugly to have object[] of object[]'s and then in code have to "know" that object[0][1] corresponds to something.
I suspect it makes sense to create a truly new class called like a FnFooReturn, but then where does it make the most sense to include the definition of such classes so that anywhere that calls the function can use it?
Edit:
A specific example:
I have a function Foo that takes in a list of objects like:
(int id, int num, string name)
so some example data could be:
(1, 100, "foo")
(1, 203, "foo")
(2, 400, "bar")
(3, 10, "cat")
and I want to return a list of objects like:
(int id, string name, int[] nums)
to look like:
[(1, "foo", [100, 103]), (2, "bar", [400]), (3, "cat", [10])]
so basically it is just a different view of the original list of objects except it combines together all of the objects with the same id to make it easier to loop over in other code later.
You can add an ordinary class to your project and use it wherever you like.
Try LINQ:
var items = new[] {
new { id = 1, num = 100, name = "foo" },
new { id = 1, num = 203, name = "foo" },
new { id = 2, num = 400, name = "bar" },
new { id = 3, num = 10, name = "cat" },
};
var result = items.GroupBy(x => x.id, (k, i) => new { id = k, nums = i.Select(y => y.num).ToArray(), name = i.Select(x => x.name).First() }).ToArray();
If you need encapsulate this logic into a method, use an Extension Method on your list (and empower it with Generics if needed).
Your functions should be like b = F(a) where a and b are menaingful types in your design.
There is some limited room for ad-hoc types, like Tuple<Customer, decimal> but if you find yourself writing special classes to accomodate a method, something has gone wrong.
In your specific example you should have a concrete type which handles those properties, and utilize LINQ to reinterpret the data in a different "view".
public class Item
{
public int Id { get; private set; }
public int Category { get; set; }
public string Name { get; set; }
public Item(int id, int category, string name)
{
this.Id = id;
this.Category = category;
this.Name = name;
}
}
Later:
var items = new [] { new Item(1, 103, "foo"), ... };
var query = from item in items
where item.Category != 108 /* example */
group by item.Id into g
select new
{
Id = g.Key,
Categories = g.Select(x => x.Category).ToArray()
};