REST API multiple endpoints design - c#

I am currently in the process of building a .NET Web API which is gonna be consumed in another project for a dashboard. Currently, first endpoint return total number of parcels and an array of parcels sent for a given date range.
An example of this API endpoint response looks something like this
{
"totalCount": 3,
"data": [
{
"parcelId": 1,
"parcelSentDate": "2022-04-25",
"parcelCount": 1
},
{
"parcelId": 2,
"parcelSentDate": "2022-04-26",
"parcelCount": 1
},
{
"parcelId": 3,
"parcelSentDate": "2022-04-27",
"parcelCount": 1
}
],
"success": true
}
Second endpoint returns a total number of parcels on whether they have been delivered either early, late or on time and has an array of parcels which contains the delivered date and the estimated delivery date.
An example of this API endpoint response looks like the below
{
"early": 1,
"late": 2,
"onTime": 0,
"data": [
{
"parcelId": 1,
"deliveredDate": "2022-05-04",
"estimatedDeliveryDate": "2022-05-02",
},
{
"parcelId": 2,
"deliveredDate": "2022-05-01",
"estimatedDeliveryDate": "2022-04-30",
},
{
"parcelId": 3,
"deliveredDate": "2021-05-26",
"estimatedDeliveryDate": "2022-05-09",
}
],
"success": true
}
The total number of parcels sent can be calculated using the second endpoint from the parcels array. What I am wondering about is, is it still okay to keep the first endpoint that returns the total number of parcels sent and keep things separated? or is it better to keep only the second endpoint and derive the total parcels count from it since it will contain all the parcels information?
Does it all come down to the situation and there isn't a right or wrong answer here?

You can keep only one endpoint but separate with any specific parameters like early, late or on time that depends on your business requirements. If these parameters passed then return the second endpoint functionality or just return the first endpoint functionality. If these parameters are not required put just one parameter like with_specifications = true and then return second endpoint functionality otherwise if it false return the first endpoint functionality.

Related

Slice array into sub-arrays of varying sizes (C#)

While doing a code Kata, I've run into a slight logical problem that I can't figure out a solution to. It isn't a hard-and-fast requirement of completing the task but it has me intrigued as to how it could be handled.
The Kata is simulating applying pricing discounts and a supermarket checkout (see full Kata here) through a collection of pricing rules. To play around with some inheritance and interface capabilities, I've added a "Buy X, get Y free" rule. It works fine when the Y in question is 1, but starts getting a little hazy after that...
For example, I experimented with the idea of "Buy 3, get 2 free". I tried doing this by grouping the items in groups of 5, and working out the discount of each group by subtracting the price of two of the items:
public override double CalculateDiscount(Item[] items)
{
//per the example described above
//_groupSize = 5, _buy = 3
//meaning 2 out of every group of 5 items should be free
var discountGroups = new List<IEnumerable<Item>>();
for (var i = 0; i < items.Length / _groupSize; i++)
{
discountGroups.Add(items.Skip(i * _groupSize).Take(_groupSize));
}
return discountGroups
.Sum(group => group
.Skip(_buy)
.Sum(item => item.Price)
);
}
What I found is that the above code works as expected (if each item has a Price property of 1.00, the above would return 2.00). An edge case that I am looking to solve is that it doesn't take affect until the fifth item is added (so the price as you ad each item would go 1.00, 2.00, 3.00, 4.00, 3.00).
What I would ideally like is that, once you have three items in your collection, the next two items are free, whether you choose to take just one or two of them shouldn't affect the price. I understand this isn't hugely realistic to the domain, but I was interested in trying to solve it as a technical problem.
I've had a few cracks at it but haven't successfully gotten any closer than the above code. I figure that what I need to do is group the array into the minimum number of bought items required, then a variable number of free items. I could probably hard-code something to solve the issue once, but this gets complicated if I were to simulate buying 3 items and getting 2 free, then buying 3 items but only taking one free one.
Any advice on how to go about this would be really appreciated!
Thanks,
Mark
Your discount-calculation has some bugs, for example you dont create groups if the item-count is less than groupSize. So change i < to i <=:
for (var i = 0; i <= items.Length / groupSize; i++)
{
discountGroups.Add(items.Skip(i * groupSize).Take(groupSize));
}
Maybe that's already all.
I would just like to add that the extension method .Chunk() was added to the System.Linq namespace in .NET 6, and it does exactly what you are doing to create discountGroups; it splits the source collection into an IEnumerable of chunks of the requested chunk size:
source: { 1, 2, 3, 4, 5, 6, 7, 8 }
var chunks = source.Chunk(3);
chunks: { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8 } }
If the item count in the source enumerable is not exactly divisible by the wanted chunk size, the last chunk will simply consist of the remaining items (i.e. the last chunk may be smaller in size than the other chunks).
By using .Chunk(), you could therefore replace this:
var discountGroups = new List<IEnumerable<Item>>();
for (...)
{
discountGroups.Add(items.Skip(i * _groupSize).Take(_groupSize));
}
with this:
var discountGroups = items.Chunk(_groupSize).ToList();

How do I initialize a list<> with two dimensional arrays?

List<int[,]> table = new List<int[,]> { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
This isn't right, but I'm stumped on how to do it.
Basically in the end I want to say table[0] and get back the first tuple, table[2] and get back the second tuple, and so on.
What is the correct format (if I have the right data model) or the correct data structure for what I want to do?
I have a pretty hefty list of tuples in the above format, And I like to stay with the format if at all possible.

Splitting tables in C# and SQL

I have got a database which I already implemented in my Web API. I am working at a summer job and I have to use C# that I have never used before. I am not the best programmer but I know how to use java.
I need to split 4 columns each. In my database, there are 4 tables:
Name (for the name of a station)
Date (for the date the company measured the data)
FeedbackType (it is a type of feedback. I got 4 types: Very Negative, Negative, Positive and Very Positive)
Count (it describes how many people voted for this specific Feedbacktype).
Every Station has a column for every FeedbackType and my problem is to summarise the feedbacks. Very Negative gives 0 points, Negative gives 1 point, Positive gives 2 points and Very Positive gives 3 points. I have to multiply "Count" with the points given.
Down below you see a little bit of my json file
{
"Name": "ASFINAG - Parkplatz Radin Nord",
"Date": "01.07.2019 00:00:00",
"FeedbackType": "Very Negative",
"Count": 3
},
{
"Name": "ASFINAG - Parkplatz Radin Nord",
"Date": "01.07.2019 00:00:00",
"FeedbackType": "Negative",
"Count": 1
},
{
"Name": "ASFINAG - Parkplatz Radin Nord",
"Date": "01.07.2019 00:00:00",
"FeedbackType": "Positive",
"Count": 9
},
{
"Name": "ASFINAG - Parkplatz Radin Nord",
"Date": "01.07.2019 00:00:00",
"FeedbackType": "Very Positive",
"Count": 7
},
This code is just one station just to show you an example of what i have to do
I hope it is not too hard to understand and I really hope you can help me
Thank you.
To Feedbacktype by its value and have a total per company:
We need a way to store Feedbacktype and its respective value. Here we can use a simple array as index will be the value but we could use a Dictionary if the value change in the future
var feedbackValue = new string[] { "Very Negative", "Negative", "Positive", "Very Positive" };
Finding the multiplicator value for a given feed back will be:
Array.IndexOf(feedbackValue, x.FeedbackType)
Then we group on Company name.
And Sum the count and feedbackValue.
data.GroupBy(x => x.Name)
.Select(g => new
{
Name = g.Key,
Total = g.Sum(x =>
x.Count * Array.IndexOf(feedbackValue, x.FeedbackType)
)
});
Result:
{ Name = Foo, Total = 40 },
{ Name = Bar, Total = 22 }
LiveDemo

Multi Label Support Vector Machine in Accord.NET

I am trying to make a Multi Label Support Vector Machine using Accord.NET framework (MultilabelSupportVectorMachine Class) but based on the example it's difficult to understand the encoding e.g.:
// Sample input data
double[][] inputs =
{
new double[] { 0 },
new double[] { 3 },
new double[] { 1 },
new double[] { 2 },
};
// Outputs for each of the inputs
int[][] outputs =
{
new[] { -1, 1, -1 },
new[] { -1, -1, 1 },
new[] { 1, 1, -1 },
new[] { -1, -1, -1 },
};
What if my output is a matrix which contains integer values not within the -1 and +1 range, what encoding should we use to convert the data into this format?
This is the format of the output the MultiLabelSupportVectorMachine would return if you compute something with it. MultiClassSupportVectorMachine returns a single int because it is used when you are sure that an example matches only a single class whereas MultiLabelSupportVectorMachine returns an array which shows which classes does the example match and is used when an example can match more classes.
It works like this:
The output array length is between 0(inclusive) and the number of classes. So if you have 4 classes you'll have an output array like this:
{ -1, -1, 1, -1 }
This means that the output class is 2, because the index of 1 is 2.
I hope that now you know how the output of this class works and that this gives you directions how to format your example output.
Additional info: If you want to use MultiLabelSupportVectorMachine, but you want to get only one output class you can just take the first index of 1 in the output array. I recommend this only if you are certain that One-Vs-All serves you better than One-Vs-One.

Number of nested loops at runtime

I am trying to output all the possible unique integer combinations from 1 to max for a set number of integers. So for 3 integers and a max of 4 I would get:
123
124
134
234
I am doing this with nested for loops but I want to allow the user to input the number of integers at runtime. right now I have
if(numInts >6);
for(int x = 1; x < max; x++);
if(numInts >5);
for(int y = 1; y < max; y++);
...
Is there a way to clean this up so I don't have to write out each possible integer for loop.
PS: I know the code above will not output the requested output. This is for a programing competition so I am not asking for code solutions just the idea that would make this possible.
One word: Recursion.
Looking at your comments on the original post, you want an iterative solution. A recursive solution will be just as fast as an iterative solution when you have a language that supports tail call optimization. But if you're working with Java/C#, again, this isn't available, so here's another way to look at the problem.
You are generating combinations. A combination is just a subset with a certain number of elements. Subsets with small-ish sets can be expressed with bitmasks.
If I have the set [1, 2, 3, 4] and I want to describe the subset [1, 3, 4], I can do so by going through each element and asking "True or False: is this element in the subset?" So, for [1, 3, 4], the result is [True, False, True, True]. If I am working with a set less than 32 (or 64) bytes, I can encode this as an integer: 1011b = 11. This is very compact in memory and computers tend to have very fast bitmath operators.
So what is a combination then, in terms of these binary numbers? If I want all subsets with N members, I can translate that as "I want all numbers with N bits set."
Take [1, 2, 3, 4] as we have been. We want all subsets with 3 elements. How many 4-bit numbers are there with exactly 3 bits set? Answer: 1110b, 1101b, 1011b, and 0111b. If we turn these integers into subsets, we get your solutions: [1, 2, 3], [1, 2, 4], [1, 3, 4], and [2, 3, 4].
You can start thinking in terms of the bits only. You start off with the lowest number with N bits set. That corresponds to a solution. You then start flipping bits one-for-one. In a systematic way such that each iteration always results in the next highest number.
Use recursion, and numInts becomes the depth of your call tree.
Check out combinations on Wikipedia. These are what you are trying to generate.
EDIT: At first, I thought the OP meant permuations. The following code doesn't work for combinations, but I'll keep it here in case someone wants to tweak it to get it to work.
As others have said, this is a problem for which recursion excels at. Let's call your function pick(num, list). Here is some pseudo code.
List pick(Int num, List list)
{
if (num == 1) // base case
{
return list
}
else // recurring case
{
var results = []
foreach (item in list)
{
alteredList = list.copy().remove(item)
results.add([item] + pick(num - 1, alteredList))
}
return results
}
}
Some notes on the above code. Note the two cases. Recursion almost always follows the base-case/recurring-case format. The actual recursion occurs in the line results.add([item] + pick(num - 1, alteredList)), and the key point is that you pass num-1. This means that in each call to pick, num gets smaller and smaller until it reaches 1 (when it reaches 1, it's done).
The variable named alteredList is created as a COPY of list with the current item removed. Most languages have a removed method, but it ALTERS the original list (this is not what you want!!) Recursion works best when variables are immutable (when they aren't altered ever).
Lastly, I want to clarify the line [item] + pick(num - 1, alteredList) a bit. I simply mean create a new list, whose first element is item and the rest of the elements are the list returned by the call pick(num - 1, alteredList). In Lisp, this operation of adding an element to the front of a list is called a cons. This cons operation is extremely powerful in functional languages, where recursion is heavily used, but it is awkward to express in imperative languages, such as Java/C#.
Problems where you would need nested for-loops usually shout for recursion.
Imagine a tree like
<root>
<1>
<1>
<1>
<2>
<3>
<4>
<2>
<1>
<2>
<3>
<4>
...
then walk through the tree (recursivly) and collect the 'valid paths'
internal class Program {
private static void Main(string[] args) {
foreach (var combination in AllCombinations(new[] { 1, 2, 3 })) {
Console.WriteLine(string.Join("", combination.Select(item => item.ToString()).ToArray()));
}
}
private static IEnumerable<IEnumerable<T>> AllCombinations<T>(IEnumerable<T> elements) {
if (elements.Count() == 1) yield return new[] { elements.First() };
else {
foreach (var element in elements) {
foreach (var combination in AllCombinations(elements.Except(new[] { element }))) {
yield return (new[] { element }).Concat<T>(combination);
}
}
}
}
}

Categories