Weighted Job Scheduler - Retrieve Job Details - c#

I am learning C# and want to created a weighted job scheduler.
The max profit is working fine. But I need to be able to get the JobIDs associated with it so I am trying to save it in an array jobsId, similar to this implementation in C++: https://onlinegdb.com/a9wx3nHoN.
But then in this snippet, I am getting an error: Wrong number of indices inside []; expected 2
if (profitSum > dp[i-1]) {
dp[i] = profitSum;
jobsId[i,0] = jobsId[task]; // Problem is here
jobsId[i].Append(jobs[i].id).ToArray(); //And here
}
What am I doing wrong? Please help, thanks!
Codes can be accessed here:
https://rextester.com/NXM85235
Alternatively, here is my entire snippet:
using System.IO;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
class Program
{
public int JobScheduling(int[] startTime, int[] endTime, int[] profit) {
var jobs = startTime
.Select((_, i) => new // create custom obj
{
id = i,
s = startTime[i],
e = endTime[i],
p = profit[i],
}
)
.OrderBy(x => x.e) // sort by end-time
.ToArray();
int[] dp = new int[jobs.Length];
int [,] jobsId = new int[,] {{jobs[0].id}};
int profitSum = jobs[0].p;
int task = -1;
dp[0] = jobs[0].p;
for (var i = 1; i < jobs.Length; i++) {
for (var j = i-1; j >= 0; j--) {
if (jobs[j].e <= jobs[i].s) {
task = j;
break;
}
}
if (task != -1) {
profitSum += dp[task];
}
if (profitSum > dp[i-1]) {
dp[i] = profitSum;
jobsId[i,0] = jobsId[task]; // Problem is here
jobsId[i].Append(jobs[i].id).ToArray();
}
}
// Need to implement this
for (var iter = 0; iter < jobsId.Length; iter++) {
Console.WriteLine(jobsId[iter,0]);
}
return dp[jobs.Length-1];
}
public static void Main(string[] args)
{
int[] startTime = { 1,3,6,2 };
int[] endTime = { 2,5,7,8 };
int[] profit = { 50,20,100,200 };
// Creating object
Program job = new Program();
Console.WriteLine(job.JobScheduling(startTime, endTime, profit));
}
}

int [,] jobsId = new int[,] {{jobs[0].id}};
The multi-dimensional 3d array that you are using has a fixed size .i.e. only one. You can't add any more elements to that array. Instead, try using List< List < int > >.
jobsId[i,0] = jobsId[task]; // problem here
Here jobsId is a 2d-array. You can't access the individual rows. You can only access elements within. For this too you need to create an array of array .i.e List< List < int > >.
And I could not figure out why are trying to get an array here.
jobsId[i].Append(jobs[i].id).ToArray();

Related

Shuffle in same order

I have a list of sprites and list of strings. I would like to shuffle this. The shuffle works but differently for both sprites and strings. Can the order of the shuffle for both be the same?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ShuffleList : MonoBehaviour
{
public List<Sprite> iconSprite = new List<Sprite>();
public List<string> priceText = new List<string>();
// Start is called before the first frame update
void Start()
{
iconSprite.Shuffle();
priceText.Shuffle();
}
}
public static class IListExtensions {
/// <summary>
/// Shuffles the element order of the specified list.
/// </summary>
public static void Shuffle<T>(this IList<T> ts) {
var count = ts.Count;
var last = count - 1;
for (var i = 0; i < last; ++i) {
var r = UnityEngine.Random.Range(i, count);
var tmp = ts[i];
ts[i] = ts[r];
ts[r] = tmp;
}
}
}
You need to shuffle both lists at once. So instead of an extension-method that only has a single parameter, just use a normal method having two lists as params.
public static void Shuffle<T1, T2>(IList<T1> list1, IList<T2> list2)
{
var count = ts.Count;
var last = count - 1;
for (var i = 0; i < last; ++i) {
var r = UnityEngine.Random.Range(i, count);
var tmp1 = list1[i];
var tmp2 = list2[i];
list1[i] = list1[r];
list1[r] = tmp1;
list2[i] = list2[r];
list2[r] = tmp2;
}
}
Alternativly you can also use the same seed for the random-generator, which will lead to identical sequences being generated:
public static void Shuffle<T>(this IList<T> ts, long seed)
{
UnityEngine.Random.InitState(seed);
var count = ts.Count;
var last = count - 1;
for (var i = 0; i < last; ++i) {
var r = UnityEngine.Random.Range(i, count);
var tmp = ts[i];
ts[i] = ts[r];
ts[r] = tmp;
}
}
Now you can provide the same seed for both calls to the function, e.g.:
void Start()
{
var seed = Datetime.Now.Ticks;
iconSprite.Shuffle(seed);
priceText.Shuffle(seed); // use the exact same seed again to produce the same random sequence
}

C# find highest value in class object array without LINQ

This is for my school project and therefor I need to code without LINQ methods etc.
I'm trying to show which city has the highest temperature by finding the highest temp and then print it together with the city name.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class City
{
public string name { get; set; }
public int temp { get; set; }
public override string ToString()
{
return $"CITY:\t{name}\nTEMP:\t{temp}°C\n";
}
}
I want to use Tostring() to print.
//=====Highest Temperature=====//
static void HighestTemp(City[] cities)
{
int highest = cities[0].temp;
for (int i = 1; i < cities.Length; i++)
{
if (highest < cities[i].temp)
{
highest = cities[i].temp;
}
}
}
I've found the highest temperature.
But the question is: How do I print it with ToString()?? I want both cities[i].name and cities[i].temp
Your issue is you found the highest temp, not the city with the highest temp.
Without using Linq or any of the shortcut methods like .OrderBy(..) or .OrderByDescending(..), you can simply just store a second variable that tracks your best i
int highestTemp = cities[0].temp;
int highestTempIndex = 0;
for (int i = 1; i < cities.Length; i++)
{
if (highest < cities[i].temp)
{
highest = cities[i].temp;
highestTempIndex = i;
}
}
var highestTempCity = cities[highestTempIndex];
And to stringify the city its as simple as:
$"{highestTempCity}"
Because overriding specifically .ToString() automates this. You also can call highestTempCity.ToString() if you like.
If you utilize the power of Linq though you can simplify this a lot by just doing:
var highestTempCity = cities.OrderByDescending(city => city.temp).First();
SOLVED!
I succeeded by doing like this:
//=====Highest temperature=====//
static int HighestTemp(City[] cities, int n)
{
int highestTemp = cities[0].temp;
var highestTempIndex = 0;
for (int i = 1; i < n; i++)
{
if (highestTemp < cities[i].temp)
{
highestTemp = cities[i].temp;
highestTempIndex = i;
}
}
return highestTempIndex;
}
From what this method return I made int Index and print the result in Main
//----------City with HIGHEST temperature----------//
index = HighestTemp(cities, n);
Console.WriteLine(cities[index].ToString());

Random.Next - Am I silently creating new instances?

Random.Next() randomness failures are almost always caused by creating and then using multiple instances of System.Random with the same seed, either with a time seed or a manual one. However, this is the only instance creation code in my class:
System.Random rNG;
if (string.IsNullOrEmpty(Map.Seed))
{
rNG = new System.Random();
}
else
{
rNG = new System.Random(Map.Seed.GetHashCode());
}
Looping through this second attempt code correctly creates random numbers:
var resourceRoll = rNG.Next(0, this.ResourceByRoll.Count);
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[resourceRoll]
))
Looping through this original attempt code often creates the same number twice in a row:
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
Am I somehow silently creating a new instance of System.Random when using a Random.Next call as a dictionary index? Why does my original code often return the same number twice in a row?
If it matters:
This class is a Unity script
I am using System.Random, not UnityEngine.Random
My complete class is below:
using Assets.Code.Tools;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using UnityEngine;
public class Map : MonoBehaviour
{
public static int Length { get; set; }
public static int Width { get; set; }
public static int ResourceChanceDenominator { get; set; }
public static string Seed { get; set; }
private static int[,] objectGrid;
private DataTable ProcGenResourceTable { get; set; }
private Dictionary<int, string> ResourceByRoll { get; set; }
private List<GameObject> prefabTrees;
private List<GameObject> prefabStones;
private void Start()
{
this.prefabTrees = GeneralTools.GetPrefabsWithTag("Tree");
this.prefabStones = GeneralTools.GetPrefabsWithTag("Stone");
GenerateMap();
}
public void GenerateMap()
{
var procGenResourceTable = Resources.Load("ProcGenResourceTable") as TextAsset;
if (procGenResourceTable != null)
{
this.ProcGenResourceTable = GeneralTools.GetDataTableFromCSV(procGenResourceTable, "|", true, false);
}
else
{
Console.WriteLine("ProcGenResourceTable could not be found");
return;
}
Map.objectGrid = new int[Map.Width, Map.Length];
this.ResourceByRoll = GetPopulatedResourceByRollDictionary();
System.Random rNG;
if (string.IsNullOrEmpty(Map.Seed))
{
rNG = new System.Random();
}
else
{
rNG = new System.Random(Map.Seed.GetHashCode());
}
for (var i = 0; i < Map.Length; i++)
{
for (var j = 0; j < Map.Width; j++)
{
var roll = rNG.Next(Map.ResourceChanceDenominator);
if (roll == 1)
{
// var resourceRoll = rNG.Next(0, this.ResourceByRoll.Count);
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
select new
{
ModelFamily = row["Model Family"],
Tags = row["Tags"]
};
foreach (var row in resourceRow)
{
GameObject resource = null;
switch (row.ModelFamily)
{
case "Tree":
resource = Instantiate(this.prefabTrees[rNG.Next(this.prefabTrees.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
case "Stone":
resource = Instantiate(this.prefabStones[rNG.Next(this.prefabStones.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
default:
resource = Instantiate(this.prefabTrees[rNG.Next(this.prefabTrees.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
}
var tagsListForResource = row.Tags.ToString().Split(new char[] { '|' }).ToList();
if (tagsListForResource.Contains("Resource"))
{
resource.tag = "Resource";
}
}
}
}
}
}
private Dictionary<int, string> GetPopulatedResourceByRollDictionary()
{
var resourceByRoll = new Dictionary<int, string>();
foreach (DataRow row in this.ProcGenResourceTable.Rows)
{
if (!string.IsNullOrEmpty(row["Weight"].ToString()))
{
for (var i = 0; i < Convert.ToInt32(row["Weight"]); i++)
{
resourceByRoll.Add(resourceByRoll.Count, row["Resource"].ToString());
}
}
}
return resourceByRoll;
}
}
I misunderstood what was going on - this is not related to repeated random numbers.
The answer to Michael Welch's question is that I am seeing trees and rocks generate on the same coordinates.
I expected this code to only generate one row of results:
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
However, it is sometimes returns more, because .Where() does some looping of its own that re-rolls the number each time.
Having multiple rows returned causes the foreach block to generate multiple prefabs at the coordinate instead of just one.

How do I replace an array element within an if statement? C#

This is the second version of this code I've gone through as the first version ran too quickly for the Random function to work properly. I'm trying to make sure none of the randomly generated numbers are the same and if they are replace them in the array but it's not letting me call the array. Can someone tell me what I'm doing wrong?
using System;
using System.Timers;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp4
{
class Program
{
public static Timer aTimer;
static void Main(string[] args)
{
//Create three different random integers and store them
Random rnd = new Random();
int RandA = rnd.Next(0, 26);
int RandB = rnd.Next(0, 26);
int RandC = rnd.Next(0, 26);
//Turn those three variables into an array
int[] RandArray = { RandA, RandB, RandC };
//Make sure there are no duplicates
if (RandArray[0] == RandArray[1])
{
int RandArray[0] = rnd.Next(0, 26);
}
if (RandArray[1] == RandArray[2])
{
int RandArray[1] = rnd.Next(0, 26);
}
if (RandArray[2] == RandArray[0])
{
int RandArray[2] = rnd.Next(0, 26);
}
//Print out all three values seperately
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Value of: {1}", i, RandArray[i]);
continue;
}
Console.ReadKey();
}
}
}
Well, I would potentially alter your approach.
public static class Randomizer
{
private static const generator = new Random();
public static int Generate(int minimum, int maximum) => generator.Next(minimum, maximum);
}
Then I would do the following:
public static class BuildRandom
{
public IEnumerable<int> FillCollection(int capacity)
{
for(int index = 0; index < capacity; index++)
yield return Randomizer.Generate(0, 26);
}
public static int GetRandomNumber() => Randomizer.Generate(0, 26);
}
Then I would simply do the following.
// Build Collection
var randomized = BuildRandom.FillCollection(5);
// Remove Duplicates
var filter = randomized.Distinct();
while(filter.Count != randomized.Count)
{
var value = BuildRandom.GetRandomNumber();
if(!filter.Any(number => number == value))
filter.Concat(new { value });
}
int RandArray[0] = is a syntax error. Try RandArray[0] =

Generate 4 differents numbers randomly

I am a novice in Xamarin ,
I want to generate randomly 4 numbers which are in a list and this 4 numbers must be different .
In the example below I have a list of Ids and I am trying to pick 4 id randomly in the list and those 4 Ids must be each differents.
Here is my methode, I cannot see how I can continue and make it simple :
public MyWordsList()
{
InitializeComponent();
Dictionary<int, int> WordId = new Dictionary<int, int>();
int u= 0;
// TestAnswer.IsVisible = false;
foreach (var w in mywords)
{
WordId[u] = w.ID;
u++;
}
Random rnd = new Random();
// this is not ok because I can have the same number
word11.Text = WordsList[rnd.Next(1, 20)];
word12.Text = WordsList[rnd.Next(1, 20)];
word13.Text = WordsList[rnd.Next(1, 20)];
word14.Text = WordsList[rnd.Next(1, 20)];
}
If you have a better solution, I will take.
Thanks
You can write a short generic function which picks X amount of random and unique items from a specified collection and returns them:
private static IEnumerable<T> GetUniqueRandomItems<T>(int count, IList<T> allItems)
{
if (new HashSet<T>(allItems).Count < count)
{
throw new ArgumentException(nameof(allItems));
}
Random random = new Random();
HashSet<T> items = new HashSet<T>();
while (items.Count < count)
{
T value = allItems[random.Next(0, allItems.Count)];
items.Add(value);
}
return items;
}
You can later use it like this:
string[] randomIds = GetUniqueRandomItems(4, WordsList).ToArray();
word11.Text = randomIds[0];
word12.Text = randomIds[1];
word13.Text = randomIds[2];
word14.Text = randomIds[3];
call a method like the following:
private int CreateUniqueRandom(int min, int max, ICollection<int> existingNums)
{
var rnd = new Random();
var newNum = rnd.Next(min, max);
while (existingNums.Contains(newNum))
newNum = rnd.Next(min, max);
return newNum;
}
Passing through a list of the numbers that you have created so far
You probably won't need this, but just to show a method of unique random number generation with no duplicate check:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var randoms = GenerateRandoms(10, 1, 10).OrderBy(v => v);
foreach (var random in randoms)
{
Console.WriteLine(random);
}
Console.ReadLine();
}
private static int[] GenerateRandoms(int randomCount, int min, int max)
{
var length = max - min + 1;
if (randomCount > length) { throw new ArgumentException($"Cannot generate {randomCount} random numbers between {min} and {max} (inclusive)."); }
var values = new List<int>(length);
for (var i = 0; i < length; i++)
{
values.Insert(i, min + i);
}
var randomGenerator = new Random();
var randoms = new List<int>();
for (var i = 0; i < randomCount; i++)
{
var val = randomGenerator.Next(0, values.Count);
randoms.Add(values[val]);
values.RemoveAt(val);
}
return randoms.ToArray();
}
}
}

Categories

Resources