Functional way to create and populate arrays in C# - c#

How can I create and populate the array in a functional way than the following imperative way?
Imperative Code
IList<Customer> customers = new List<Customer>();
// my input data is array of strings
string[] ids = {"4", "6"};
string[] names = {"John Doe", "Jane Doe"};
for (var i = 0; i<ids.Length; i++)
{
customers.Add(new Customer
{
Id = Int32.Parse(ids[i]),
Name = names[i],
});
}
Customer class
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}

Something like this?
customers = ids.Zip(names, (id, name) => new Customer { Id = Int32.Parse(id), Name = name }).ToList();

If by functional you mean without loops, you can use LINQ's Zip to combine values and produce an IEnmerable<Customer> :
var customers=ids.Zip(names,(id,name)=> new Customer
{
Id = Int32.Parse(ids[i]);
Name = names[i];
})
.ToArray();
//Or .ToList(); if a List<T> is preferable
I say if because creating the array still requires allocating an array and modifying it.It's actually more expensive thatn creating an array in advance because ToArray() doesn't know how big an array to create, so it may need to reallocate its internal buffers.
A more functional approach would be to consume the IEnumerable<Customer> produced by Zip. That sequence of customer objects can be consumed by any other LINQ operator or custom methods that expect an IEnumerable<T>.
A more performant version would create the array in advance and copy the values from the IEnumerable produced by zip :
var customers=new Customer[ids.Length];
var values=ids.Zip(names,(id,name)=> new Customer
{
Id = Int32.Parse(ids[i]);
Name = names[i];
});
var i=0;
foreach(var values)
{
customers[i++]=v;
}

Related

How to get the first value in Dictionary< string, int > #shorthand

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.

How to yield multiple objects with respect to a multi-valued column in Dynamic Linq

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.

How to create a tuple of <string, List<myobject>> from datasource with comma delimited IDs

I have this object
[Serializable]
public class Modulo
{
[Key]
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public int Id { get; set; }
public string Nombre { get; set; }
public string ClaseFontAwesome { get; set; }
}
Modulos are per user, so One user can have many modules.
SO I need to know how to create this tuple with the list of modulos:
Tuple<string, List<Modulo>> modulosPorUsuarioDeDirectorioActivo;
Dont worry too much about the technical details of the code below, I just have an azure active directory with a schema extension (custom property), that schema extension saves the modules for one user in this format: 1,2,5,7
var extPropLookupNameModulos = $"extension_{SettingsHelper.ClientId.Replace("-", "")}_{"Modulos"}";
var client = AuthenticationHelper.GetActiveDirectoryClient();
var user = await client.Users.GetByObjectId(identityname).ExecuteAsync();
var userFetcher = (User)user;
var unitOfWork = new UnitOfWork();
var keyvaluepairModulos = userFetcher
.GetExtendedProperties()
.FirstOrDefault(prop => prop.Key == extPropLookupNameModulos);
var idsModulos = keyvaluepairModulos.Value.ToString().Split(',');
foreach (var idModulo in idsModulos)
{
var modulo =
unitOfWork.ModuloRepository.GetById(Convert.ToInt32(idModulo));
}
But I dont know how to create the Tuple object inside the foreach.
Procedurally, you would create a List<Modulo> and fill it inside the for loop by adding Modulo instances for each id, and then create the tuple after the loop.
But a simpler way (well, less typing anyway) might be to use LINQ; Select method can project each id into a Modulo instance:
// split the string into an array of int ids
var idsModulos = keyvaluepairModulos.Value.ToString().Split(',');
// project each id into a modulo instance
var listOfModulos = idsModulos
.Select(id => unitOfWork.ModuloRepository.GetById(Convert.ToInt32(id)))
.ToList();
// it's simpler to use Tuple.Create instead of the Tuple constructor
// because you don't need to specify generic arguments in that case (they are infered)
var tuple = Tuple.Create(name, listOfModulos);
In c#, you create Tuples the same way you create any object.
var tuple = new Tuple<string, List<Modulo>>("string", new List<Modulo>());
https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx

C# Complex Return Types

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()
};

Create a class with array of objects

Code below defines a ChargeCustomer class that contains an array of type "customers". I want to be able to create an object with either 1 "customer" or 2 "customers" based on the constructor parameters. Is this the right way to do so in C#:
public class ChargeCustomer
{
private Customer[] customers;
public ChargeCustomer( string aName, string bName, int charge )
{
customers = new Customer[2];
customers[0] = new Customer(aName, charge);
customers[1] = new Customer(bName, charge);
}
public ChargeCustomer( string bName, int charge )
{
customers = new Customer[1];
customers[0] = new Customer( bName, charge );
}
}
Thanks!
Note: This assumes that DropBox was a mis-paste in the original question.
You can move things around and have 1 constructor using params for any number of names, like this:
public class ChargeCustomer
{
private Customer[] customers;
public ChargeCustomer( int charge, params string[] names)
{
customers = new Customer[names.Length];
for(int i = 0; i < names.Length; i++) {
customers[i] = new Customer(names[i], charge);
}
}
}
Using this approach you just pass the charge first and any number of customer names, like this:
new ChargeCustomer(20, "Bill", "Joe", "Ned", "Ted", "Monkey");
It will create an array the correct size and fill it using the same charge for all, and 1 Customer per name by looping through the names passed in. All that being said, there's probably a much simpler overall solution to your problem, but without making changes outside the Customer class (aside from the constructor calls), this would be the simplest approach/smallest change.

Categories

Resources