Google ortools - capacitated vehicle routing pb - c#

The problem with the following code is :
even if I only have 10 locations to deliver and one depot set at location 0 , in this example, vehicles 1,2,3,4 seem to have they're depot at locations 10,11,12,13. Those locations don't exists. The 10 that I have are numbered from 0-9.
On the other hand the business logic seems to be OK :
as I isolated the cost of leaving the depot and the one of going back to it ( value 10 ) I get the expected result : 104. There are only 4 trips between cities that don't include the depot.
Is this a bug in Google or-tools ?
public static void Main(string[] args)
{
new CVRP().Solve(10);
}
private class RandomManhattan : NodeEvaluator2
{
public override long Run(int first_index, int second_index)
{
if (first_index == 0 || second_index == 0)
return 10;
return 1;
}
};
private class Demand : NodeEvaluator2
{
public override long Run(int first_index, int second_index)
{
return 1;
}
};
private void Solve(int locations)
{
var nr_vehicle = 5;
var routing = new RoutingModel(locations, nr_vehicle, new[] {0, 0, 0, 0, 0}, new[] {0, 0, 0, 0, 0});
Console.WriteLine("Depot : " + routing.GetDepot());
NodeEvaluator2 demandCallback = new Demand();
routing.AddDimension(demandCallback, 0, 3, true, "capacity");
var distances = new RandomManhattan();
routing.SetCost(distances);
var searchParameters =
RoutingModel.DefaultSearchParameters();
searchParameters.FirstSolutionStrategy =
FirstSolutionStrategy.Types.Value.PathCheapestArc;
var solution = routing.SolveWithParameters(searchParameters);
if (solution != null)
{
var output = "Total cost: " + solution.ObjectiveValue() + "\n";
// Dropped orders
var dropped = "";
for (var order = 0; order < locations; ++order)
{
if (solution.Value(routing.NextVar(order)) == order)
{
dropped += " " + order;
}
}
if (dropped.Length > 0)
{
output += "Dropped orders:" + dropped + "\n";
}
// Routes
for (var vehicle = 0; vehicle < nr_vehicle; ++vehicle)
{
var route = "Vehicle " + vehicle + ": ";
var order = routing.Start(vehicle);
if (routing.IsEnd(solution.Value(routing.NextVar(order))))
{
route += "Empty";
}
else
{
for (; !routing.IsEnd(order); order = solution.Value(routing.NextVar(order)))
{
var local_load = routing.CumulVar(order, "capacity");
route += order + " Load(" + solution.Value(local_load) + ") -> ";
}
if (route.Length > 0)
route = route + "0";
}
output += route + "\n";
}
Console.WriteLine(output);
}
}

You have to wrap order in
route += order + " Load(" + solution.Value(local_load) + ") -> ";
inside model.IndexToNode(order), like this
route += model.IndexToNode(order) + " Load(" + solution.Value(local_load) + ") -> ";

Related

how to get more than 5000 entities by using Factories GetByFilter method with prestasharp

Library Version:
1.2.9
NuGet Package Url:
https://www.nuget.org/packages/PrestaSharp/1.2.9
Prestashop version:
1.7.7.0
Describe the Bug:
PrestaSharp GetByFilter with pagination always return same entity list
Since ProductFactory's GetByFilter method returns null if there are more than 5000 products that match the filter. I decide to get them by pagination like this
_productFactory.GetIdsByFilter(filter, null, "[" + startingIndex.ToString() + "," + count.ToString() + "]");
but even if startingIndex(because of a loop) changes the result is the same
Full code:
filter.Add("date_upd", "[" + dFrom + "," + dTo + "]");
int i = 0;
List<long> AllProducts = new List<long>();
List<long> products;
while (true) // this loop never breaks
{
int startingIndex = i++ * count;
products = _productFactory.GetIdsByFilter(filter, null, "[" + startingIndex.ToString() + "," + (count).ToString() + "]"); // returns same products in every iteration
if (products?.Any() == true) // to check the list is not empty
{
AllProducts.AddRange(products);
if (products.Count < count)
{
break;
}
}
else
break;
}
You just have to remove the brackets from the 'limit' parameter. It is an error in the Github documentation when they give the example with brackets. Here's an own implementation where I send multiple requests in parallel to speed up the processing, regards.
public async Task<List<PS_Entity>> GetElements(int pageSize = 100) {
try {
var numberOfElements = factory.GetIds().Count;
var numberOfParallelTasks = numberOfElements >= pageSize ? numberOfElements / pageSize : 1;
var loadElementsTasks = Enumerable.Range(0, numberOfParallelTasks).Select(taskNumber => factory.GetByFilterAsync(null, "id_ASC", $"{taskNumber * pageSize},{pageSize}")).ToList();
if (numberOfElements % pageSize != 0) {
var skiped = numberOfParallelTasks * pageSize;
loadElementsTasks.Add(factory.GetByFilterAsync(null, "id_ASC", $"{skiped},{numberOfElements - skiped}"));
}
var elements = (await Task.WhenAll(loadElementsTasks)).SelectMany(elements => elements).ToList();
return elements;
} catch (PrestaSharpException e) {
if ((int)e.ResponseHttpStatusCode == 404)
Console.WriteLine($"No existen {RemoveFactoryFromName(factory)}'s.");
return new List<PS_Entity>();
}
}

Parsing list of string containing a delimiter to tree structure

So I have a list of strings like so:
var drinks = new List(){"Drinks", " * ", "Rum", "Captain Morgan", "Kraken", " * ", "Whiskey",
"Laphroaig"}
It needs to return the following:
*Drinks
*Drinks * Rum
*Drinks * Rum * Captain Morgan
*Drinks * Rum * Kraken
*Drinks * Whiskey
*Drinks * Whiskey * Laphroaig
So as seen, anytime a * is encountered, the next string would be treated as a child under the root. So here, Rum would fall under Drinks and Captain Morgan and Kraken would fall under Rum. Whiskey would fall under Drinks and Laphroaig would fall under whiskey.
I know it has to be some sort of tree structure and the only thing I have right now is this:
private static Drink GroupDrinks(List<string> drinkNames)
{
var drink = new Drink() { Children = new List<Drink>() };
foreach (var drinkName in drinkNames)
{
if (drinkName != "*")
{
drink.Name = drinkName;
drinkNames.RemoveAt(0);
}
else
{
drinkNames.RemoveAt(0);
drink.Children.Add(GroupDrinks(drinkNames));
}
}
return drink;
}
I figured I'd need to do some kind of recursion and maybe remove the character so it doesn't affect the next iteration but this clearly isn't working. Any tips would be great.
I am not sure if this code work for you but it is tested as your expected output:
Declaration:
List<Drink> lstdrink = new List<Drink>();
public List<FinalDrink> lstFinalDrink = new List<FinalDrink>();
Class:
public class FinalDrink
{
public string name { get; set; }
}
public class Drink
{
public string name { get; set; }
public int Tag { get; set; }
}
Set Up the Value:
public List<Drink> SetUpTheValue()
{
var drinks = new List<string> { "Drinks", " * ", "Rum", "Captain Morgan", "Kraken", " * ", "Whiskey", "Laphroaig" };
var repl = drinks.Select(s => s.Replace('*', ' ')).ToList();
string tag = string.Empty;
Drink drk = new Drink();
lstdrink = new List<Drink>();
for (int i = 0; i < repl.Count; i++)
{
if (i == 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 1;
lstdrink.Add(drk);
tag = repl[i];
continue;
}
if (tag.Trim().Length == 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 2;
lstdrink.Add(drk);
tag = repl[i];
continue;
}
if (repl[i].ToString().Trim().Length > 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 0;
lstdrink.Add(drk);
tag = repl[i];
}
tag = repl[i];
}
return lstdrink;
}
Group Drinks:
public List<FinalDrink> GroupDrinks(List<Drink> drinkNames)
{
lstFinalDrink = new List<FinalDrink>();
FinalDrink fDrink = new FinalDrink();
var GetFirst = drinkNames.Where(x => x.Tag == 1).ToList();
fDrink.name = GetFirst[0].name.ToString();
lstFinalDrink.Add(fDrink);
var Content = drinkNames.Where(x => x.Tag != 1).ToList();
string itrVal = string.Empty;
int prev = 0;
string hcur = string.Empty;
for (int i = 0; i < Content.Count(); i++)
{
if (Content[i].Tag == 2)
{
hcur = GetFirst[0].name + " * " + Content[i].name;
fDrink = new FinalDrink();
itrVal = GetFirst[0].name + " * " + Content[i].name;
fDrink.name = itrVal;
lstFinalDrink.Add(fDrink);
prev = Content[i].Tag;
itrVal = string.Empty;
}
else
{
fDrink = new FinalDrink();
itrVal = hcur + " * " + Content[i].name;
fDrink.name = itrVal;
lstFinalDrink.Add(fDrink);
prev = Content[i].Tag;
itrVal = string.Empty;
}
}
return lstFinalDrink;
}
Execution:
private void button1_Click(object sender, EventArgs e)
{
if (SetUpTheValue().Count() > 0)
{
GroupDrinks(lstdrink);
}
}
The GroupDrinks return List<FinalDrink> this is the final result.
It is depend on you to modify the result
This Code will return the expected output as you added from above.

C# Loop over all possible values, when not found increase value and continue

I need to send a request for every supplier code to a webservice (i know that sounds crazy but the owner designed it this way).
The supplier code format is:
30X1X1XXXXX1
You can check what i did so far (github link: https://github.com/rareba/SiapWebServices_Library/blob/master/SiapWebServices_Library/SiapWebServicesFornitore.cs)
public static List<StructAnaFornitoreOut> Get_All_Suppliers(WebServicesFornitoreClient client, StructLogin loginCredentials, string showSuspended = "N", string searchType = "R")
{
var supplier_list = new List<StructAnaFornitoreOut>();
var supplier_retrived = new StructAnaFornitoreOut
{
esito = new StructEsito
{
stato = "OK",
}
};
int KO_Count = 0;
int conto = 1;
int sottoconto = 1;
int codice = 0;
string codFornitore = Generate_Supplier_Code_String(codice, sottoconto, conto);
var search = new StructAnaFornitoreIn
{
IAnaFornitore = new StructAnaFornitore
{
codice = codFornitore
},
IAzione = "C",
//vModRicerca = new string[] { "COD_FIS","PAR_IVA","ALT_SIS" }
};
while (KO_Count < 10)
{
while (KO_Count < 10)
{
while (KO_Count < 10)
{
supplier_retrived = client.gestioneAnagraficaFornitore(loginCredentials, search);
if (supplier_retrived.esito.stato == "KO")
{
KO_Count++;
}
else
{
supplier_list.Add(supplier_retrived);
codFornitore = Generate_Supplier_Code_String(codice, sottoconto, conto);
Console.WriteLine(codFornitore);
codice++;
search.IAnaFornitore.codice = codFornitore;
}
}
KO_Count = 0;
sottoconto++;
}
KO_Count = 0;
conto++;
}
return supplier_list;
}
// Returns a supplier code string increased by 1
public static string Generate_Supplier_Code_String(int codice = 0, int sottoconto = 1, int conto = 1, string mastro = "30")
{
codice++;
string string_conto = " ";
string string_sottoconto = " ";
string string_codice = " ";
if (conto > 9)
{
string_conto = "";
}
if (sottoconto > 9)
{
string_sottoconto = "";
}
if (codice > 9)
{
string_codice = " ";
}
else if (codice > 99)
{
string_codice = " ";
}
else if (codice > 999)
{
string_codice = " ";
}
else if (codice > 9999)
{
string_codice = " ";
}
else if (codice > 99999)
{
string_codice = " ";
}
else if (codice >= 999999)
{
string_codice = "";
}
string customercode = mastro + string_conto + conto + string_sottoconto + sottoconto + string_codice + codice;
return customercode;
}
However this doesn't work at all: it stops at supplier 30 1 1 100 and starts increasing sottoconto like there is no tomorrow.
The idea should be to do something like:
- Get the supplier data
- Increase codice by 1
- If for 10 times you get nothing (esito.status = "KO") then increase sottoconto and start again from codice = 1
- If after incresing sottoconto you still get nothing for 10 times then increase conto and start again from codice = 0

Custom OrderBy on a List based on a string property value

I have the following class :
public class Document
{
public string DocumentSection { get; set; }
public string DocumentName { get; set; }
}
and I would like to order the following list based on the DocumentSection property:
List<Document> documents = new List<Document>();
documents.Add(new Document { DocumentSection = "Section One", DocumentName = "doc1" });
documents.Add(new Document { DocumentSection = "Section Two", DocumentName = "doc1123" });
documents.Add(new Document { DocumentSection = "Section Three", DocumentName = "doc113" });
documents.Add(new Document { DocumentSection = "Section Four", DocumentName = "doc123" });
documents.Add(new Document { DocumentSection = "Section Five", DocumentName = "doc11" });
In theory I know that I should implement IComparer to obtain that, but this is where the difficulty comes in, I am not very sure how can I achieve that on a general level ... what is the best solution to achieve this ordering ?
Try this:
var orderedList = documents.OrderBy(r => GetOrder(r.DocumentSection));
and the GetOrder() method is:
Public Static int GetOrder(string _arg)
{
switch (_arg)
{
case 'Section One':
return 1;
case 'Section Two':
return 2;
case 'Section Three':
return 3;
.
.
.
default:
return int.MaxValue;
}
}
easiest way is to use Linq :
List<Order> SortedList = objListOrder.OrderBy(o=>o.Order).ToList();
Sample :
List<Document> SortedList = documents.OrderBy(o=>o.DocumentName).ToList();
Long Answer
you need to customize above order method but you don't need to type all number in this code
with wordify method you can convert number to word and
with normalize_number method we normalize both result word and first word so we can check result word with first word
we have a loop and we don't like to create word always so we can use from Dictionary and check number, we do this in get_wordify method.
now with SetOrder we can find correct order
So Just Use from this code :
private int current_order = 0;
private int SetOrder(string _arg)
{
string number = _arg.ToLower()
.Replace("section", "")
.TrimStart(' ')
.TrimEnd(' ');
number = normalize_number(number);
for (int i = 0;
//you can limit loop here (i<99999) or not !
; i++)
{
string wordify_number = get_wordify(i);
if (wordify_number == number)
{
//if all number is available return i+1
//return i + 1;
//otherwise
current_order++;
return current_order;
}
}
}
private string normalize_number(string number)
{
number = number.Replace("-", " ")
.Replace("_", " ")
.Replace(",", " ");
//also you can replace "and" if you want
//.Replace(" ", " ");
//regex is better for find and replace multi space
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);
number = regex.Replace(number, " ");
return number;
}
Dictionary<int, string> Numbers_dic = new Dictionary<int, string>();
private string get_wordify(int i)
{
string wordify_number = "";
if (Numbers_dic.ContainsKey(i))
{
wordify_number = Numbers_dic[i];
}
else {
wordify_number = wordify(i);
wordify_number = normalize_number(wordify_number);
Numbers_dic.Add(i, wordify_number);
}
return wordify_number;
}
private string wordify(decimal number)
{
if (number == 0) return "zero";
var units = " one two three four five six seven eight nine".Split();
var teens = " eleven twelve thir# four# fif# six# seven# eigh# nine#".Replace("#", "teen").Split();
var tens = " ten twenty thirty forty fifty sixty seventy eighty ninety".Split();
var thou = " thousand m# b# tr# quadr# quint# sext# sept# oct#".Replace("#", "illion").Split();
var minus_str = (number < 0) ? "minus " : "";
var res_number = "";
var p = 0;
number = Math.Abs(number);
while (number > 0)
{
int b = (int)(number % 1000);
if (b > 0)
{
var h = (b / 100);
var t = (b - h * 100) / 10;
var u = (b - h * 100 - t * 10);
var str = ((h > 0) ? units[h] + " hundred" + ((t > 0 | u > 0) ? " and " : "") : "")
+ ((t > 0) ? (t == 1 && u > 0) ? teens[u] : tens[t] + ((u > 0) ? "-" : "") : "")
+ ((t != 1) ? units[u] : "");
str = (((number > 1000) && (h == 0) && (p == 0)) ? " and " : (number > 1000) ? ", " : "") + str;
res_number = str + " " + thou[p] + res_number;
}
number = number / 1000;
if (number < 1)
{
break;
}
p++;
}
return minus_str + res_number;
}
Usage :
private void Do_order()
{
var orderedList = documents.OrderBy(r => SetOrder(r.DocumentSection));
}

TaskFactory changing parameters

So i have the following code:
public void tViewers(int? start, int? stop)
{
for (int? i0 = start; i0 <= stop; i0++)
{
StartLabel:
Viewer v = new Viewer(channelNameTextBox.Text, this);
if (urlWithTokens.Contains(v.getViewerLink()))
{
goto StartLabel;
}
else
{
if (v.getViewerLink() != "")
{
Console.WriteLine("[V #" + i0 + "] SUCCESS");
urlWithTokens.Add(v.getViewerLink());
}
else
{
Console.WriteLine("Channel not found.");
showError("The channel name is not valid.", true);
this.Invoke(new Action(() => this.botControlls.Enabled = true));
urlWithTokens.Clear();
}
}
v = null; // clear
}
Console.WriteLine("[V] " + start + " to " + stop + " COMPLETED");
start = null;
stop = null;
GC.SuppressFinalize(this);
}
Which is executed by:
for (int i = 0; i < maxThreads; i++)
{
taskFactory.StartNew(() => tViewers(someValue, someHigherValue));
}
The problem here is the local parameters "start" and "stop" in tViwers and it returst some stange values.
fx if i print "start" it should return the "someValue" and "someHigherValue" depending on what "thread" it is running in, however it returns strange values 40, 50 or something (even if it should return 1, 2, 3...
I have tried using the GC.SuppressFinalize(this); and setting the int's to null my allowing them to be null (int?). However the problem is still there...
Can someone help me?

Categories

Resources