I need to find if the playlist is repeating. From my below code pls help to suggest a solution.
A playlist is considered a repeating playlist if any of the songs contain a reference to a previous song in the playlist. Otherwise, the playlist will end with the last song which points to null.
using System;
public class Song
{
private string name;
public Song NextSong { get; set; }
public Song(string name)
{
this.name = name;
}
public bool IsRepeatingPlaylist()
{
if(this.name == NextSong.name)
{
return true;
}
else
{
return false;
}
}
public static void Main(string[] args)
{
Song first = new Song("Hello");
Song second = new Song("Eye of the tiger");
first.NextSong = second;
second.NextSong = first;
Console.WriteLine(first.IsRepeatingPlaylist());
}
}
This would appear to be equivalent to checking for cycles in a linked-list, so we can simply use Floyd's "Tortoise and Hare" cycle detection algorithm:
public bool IsRepeatingPlaylist()
{
var tortoise = this;
var hare = NextSong;
while (tortoise is not null && hare is not null)
{
if (ReferenceEquals(tortoise, hare))
return true;
tortoise = tortoise.NextSong;
hare = hare.NextSong?.NextSong; // Twice as fast.
}
return false;
}
Here's some code that tests a playlist where the end of the play list loops back to a song about halfway through the playlist:
static void Main()
{
Song start = new Song("1");
Song curr = start;
Song halfway = null;
for (int i = 2; i < 100; ++i)
{
curr.NextSong = new Song(i.ToString());
curr = curr.NextSong;
if (i == 50)
halfway = curr;
}
curr.NextSong = halfway;
Console.WriteLine(start.IsRepeatingPlaylist());
}
public boolean isRepeatingPlaylist() {
Song next = this.NextSong;
while (next != null) {
if (next.name.equalsIgnoreCase(name)) {
return true;
}
next = next.NextSong;
}
return false;
}
If playlist repeats, starting songs can be skipped.
To respond to this condition we need to use collections to register every song to ensure that aren't no circular playlist at the medium.
The use of HashSet is to ensure that our script is runing fine on a large playlist.
public bool Contains (T item);
The time complexity of this method is O(1).
public bool IsRepeatingPlaylist()
{
var playList = new HashSet<Song>(){this};
var song = this.NextSong;
while (song != null) {
if (playList.Contains(song)) {
return true;
} else {
playList.Add(song);
song = song.NextSong;
}
}
return false;
}
public bool IsRepeatingPlaylist()
{
var first = this;
var second = NextSong;
while (first is not null && second is not null)
{
if (ReferenceEquals(first, second))
return true;
first = first.NextSong;
second = second.NextSong?.NextSong; // Twice as fast.
}
return false;
}
Create a list for playlist songs. Before adding a next song to list, check if song is not null and if it already exist in list.
If null, not a repetitive playlist.
if doesn't exist, add to list and continue the logic.
If exists, its repetitive playlist.
public bool IsInRepeatingPlaylist()
{
List<string> songsList = new List<string>();
songsList.Add(this.name);
Song thenext = this.NextSong;
while (thenext != null)
{
if (songsList.Contains(thenext.name))
{
return true;
}
else
{
songsList.Add(thenext.name);
thenext = thenext.NextSong;
}
}
return false;
}
Related
I am currently making an application which tracks information on players and monsters for a tabletop game.
Currently I've got classes for "Monsters". This class contains information such as its name, maxHP, speed, attacks etc. I've managed to make a Database which contains the default values for each type of monster. What I currently need to do is make it possible to change things such as name (Monster > Monster 1, Monster 2 etc), change its HP, and some other things.
I understand that I need to make a copy of such, but I am uncertain on how to do this.
What I currently tried is the following:
public class DatabaseService
{
public List<Player> Players { get; set; }
public List<Monster> AllMonsters { get; set; }
public List<Monster> ActiveMonsters = new List<Monster>();
public bool RollForHP = false;
//Main Database Service
public DatabaseService()
{
Players = GetPlayers();
AllMonsters = GetAllMonsters();
}
public void DoStuff()
{
AddMonsterByName("Goblin", 2);
AddMonsterByName("Adult White Dragon", 1);
AddMonsterByName("Duergar", 4);
foreach (Monster monster in ActiveMonsters) { Console.WriteLine(monster.Name); }
}
//Converts the .json list with all players to Classes, which are then stored in the list "Players" if the "IsInParty" is true
private List<Player> GetPlayers()
{
var path = #"C:\Users\MyName\source\repos\DndAdvancedInitiativeTracker\Logic\Database\Players.json";
var json = File.ReadAllText(path);
var players = JsonConvert.DeserializeObject<List<Player>>(json);
List<Player> inPartyPlayers = new List<Player>();
foreach (var player in players)
{
if (player.IsInParty == true) { inPartyPlayers.Add(player); }
}
return inPartyPlayers;
}
//Converts the .json list with all monsters to Classes, which are then stored in the list "AllMonsters"
private List<Monster> GetAllMonsters()
{
var path = #"C:\Users\MyName\source\repos\DndAdvancedInitiativeTracker\Logic\Database\Monsters.json";
var json = File.ReadAllText(path);
var monsters = JsonConvert.DeserializeObject<List<Monster>>(json);
return monsters;
}
//Adds a given monster to the "ActiveMonsters" list
public void AddMonsterByName(string monsterName, int amountOfMonsters)
{
for (int i = 0; i < amountOfMonsters; i++)
{
List<Monster> DatabaseCopy = AllMonsters.Clone();
DatabaseCopy = AllMonsters;
Monster monster = DatabaseCopy.Find(x => x.Name == monsterName);
Console.WriteLine(monster.Name);
var number = CheckIfNameExistsInList(monsterName);
monster.Name = monsterName + " " + (number + i).ToString();
ActiveMonsters.Add(monster);
}
}
private int CheckIfNameExistsInList(string monsterName)
{
var counter = 1;
foreach (var monster in ActiveMonsters)
{
if (monster.Name.Contains(monsterName))
{
counter += 1;
}
}
return counter;
}
}
In the "DoStuff" Method, I try to add 2 goblins, then a dragon, then a goblin again. The first goblin is named to "Goblin 1" correctly, but the second loop fails, because the AllMonsters' name for goblins is now "Goblin 1" because of the reference type, therefore, the second "Goblin" search in AllMonsters is never found, and returns null.
I'm not sure why you're copying your database (and doing so for every iteration of a for loop which is quite wasteful), but your current check code CheckIfNameExistsInList will always return 1 even if there are no matches in the list.
You can simplify your AddMonstersByName (and use a simple check for previous monster entries) as follows:
public void AddMonstersByName(string name, uint number = 1)
{
var count = AllMonsters.Count(x => x.Name.Contains(name));
for (var i = 1; i <= number; i++)
{
var num = count + i;
AllMonsters.Add(new Monster(){Name= name+num.ToString()});
}
}
This was tested in a simple Console App:
var dataService = new DataService();
dataService.AddMonstersByName("Goblin", 2);
dataService.AddMonstersByName("Dragon", 2);
dataService.AddMonstersByName("Goblin", 2);
foreach (var monster in dataService.AllMonsters)
{
Console.WriteLine($"{monster.Name}");
}
where
public class DataService
{
public List<Monster> AllMonsters = new List<Monster>();
public void AddMonstersByName(string name, uint number = 1)
{
var count = AllMonsters.Count(x => x.Name.Contains(name));
for (var i = 1; i <= number; i++)
{
var num = count + i;
AllMonsters.Add(new Monster(){Name= name+num.ToString()});
}
}
}
public class Monster
{
public string Name { get; set; }
}
I have this really weird bug where I cannot seem to delete an object from a list. I am using an Injector class to pass the same object(thus the same list) around into multiple forms. The Delete() function is just a generic delete, really nothing special. However in my unit test it keeps failing and I'm unsure why.
Injector class:
[Serializable]
public class InjectorClass
{
public OrderAdministration Administration { get; private set; }
public WareHouse WareHouse { get; private set; }
public InjectorClass()
{
Administration = new OrderAdministration(this);
WareHouse= new WareHouse();
}
}
Constructor of the WareHouse class:
public List<Part> Catalogus { get; private set; }
public List<Part> PartsInStock { get; private set; }
public WareHouse()
{
PartsInStock = new List<Part>();
AddStandardStockToCatalogus();
AddStockPartsToStock();
}
private void AddStandardStockToCatalogus()
{
Body body1 = new Body("Body7zk", 1, "Ebony", "Blue");
Body body2 = new Body("SuperXtrem368", 2, "Maple", "Red");
Neck neck1 = new Neck("Heavy-Slider", 3, "Juniper", true);
Neck neck2 = new Neck("SlickFingerBoard", 4, "Oak", false);
Fretboard fretboard1 = new Fretboard("PrettySlamFinger", 5, "Oak", false);
Fretboard fretboard2 = new Fretboard("GentleToucher", 6, "Ebony", true);
Pickups pickups1 = new Pickups("TubeScreamers", 7, Pickups.PickupType.P90);
Pickups pickups2 = new Pickups("BluesBrothers", 8, Pickups.PickupType.Humbucker);
Bridge bridge1 = new Bridge("MetalGearRipper", 9, false);
Bridge bridge2 = new Bridge("BridgeOfLove", 10, true);
Catalogus = new List<Part> { body1, body2, neck1, neck2, fretboard1, fretboard2, pickups1, pickups2, bridge1, bridge2};
}
private void AddStockPartsToStock()
{
foreach(Part p in Catalogus)
{
PartsInStock.Add(p);
}
}
The Delete() function in the same Warehouse class:
public int GetStock(Part neededPart)
{
if(neededPart == null)
{
throw new ArgumentNullException();
}
int numberInStock = 0;
foreach(Part p in PartsInStock)
{
if(p.Id == neededPart.Id)
{
numberInStock++;
}
}
return numberInStock;
}
public bool AddToStock(Part arrivedPart)
{
if(arrivedPart == null)
{
throw new ArgumentNullException();
}
if(FindByName(arrivedPart.Name).Name == arrivedPart.Name)
{
PartsInStock.Add(arrivedPart);
return true;
}
return false;
}
public bool RemovePart(Part usedPart)
{
if (GetStock(usedPart) >= 1)
{
PartsInStock.Remove(usedPart);
return true;
}
return false;
}
The unit test I run:
Neck neck1 = new Neck("Heavy-Slider", 3, "Juniper", true);
InjectorClass injector = new InjectorClass();
Assert.AreEqual(10, injector.WareHouse.PartsInStock.Count);
injector.WareHouse.RemovePart(neck1);
Assert.AreEqual(9, injector.WareHouse.PartsInStock.Count);
The output on both the assert functions is 10
Edit:
I have re-written my search and delete function to the following:
Search function:
public Part FindByNameStock(Part neededPart)
{
if (neededPart == null)
{
throw new ArgumentNullException();
}
foreach (Part p in PartsInStock)
{
if (p.Name == neededPart.Name)
{
return p;
}
}
return null;
}
Delete function:
public bool RemovePart(Part usedPart)
{
Part part = FindByNameStock(usedPart);
if (part != null)
{
PartsInStock.Remove(part);
return true;
}
return false;
}
The code now works and the unit test too.
This line PartsInStock.Remove(usedPart); will try to remove the following object
new Neck("Heavy-Slider", 3, "Juniper", true);
which is not in your list. The reason is that reference type equality is not based on the properties, but on the actual reference. Whenever you run new a new reference is created.
var neck1 = new Neck("Heavy-Slider", 3, "Juniper", true);
var neck2 = new Neck("Heavy-Slider", 3, "Juniper", true);
Console.WriteLine(neck1 == neck2); //This is false
Check the code here for an example: https://dotnetfiddle.net/7gAWID
Check here for the IEquatable implementation that will make your code work.
Two separate objects of Neck although having the same ID are different objects and hence the item is never removed.
Moreover, you can return the value of List.Remove as it also returns a bool if an item was actually removed. So if no item was removed, it returns false:
public bool RemovePart(Part usedPart)
=> GetStock(usedPart) >= 1 ?
PartsInStock.Remove(usedPart);
: false;
Use RemoveAll() to remove the item by ID. RemoveAll() returns an int representing the number of items removed:
public bool RemovePart(Part usedPart)
{
if (GetStock(usedPart) >= 1)
{
PartsInStock.RemoveAll(part => part.Id == usedPart.Id);
return true;
}
return false;
}
Also, since your RemovePart returns a bool. You can add a check to ensure if it was removed.
if (injector.WareHouse.RemovePart(neck1))
{
Assert.AreEqual(9, injector.WareHouse.PartsInStock.Count);
}
GetStock uses the Id of the part to find it, whereas PartsInStock.Remove tries to remove the part by reference - and the reference you have is different to the item in the collection you're trying to remove from.
public bool RemovePart(Part usedPart)
{
if (GetStock(usedPart) >= 1) // item is found here
{
PartsInStock.Remove(usedPart); // but usedPart is a different reference - nothing is removed
return true;
}
return false;
}
this below to sample code;
private ExampleStatus _status;
public ExampleStatus status
{
get
{
if (_status == null) _status = new ExampleStatus();
//if (_status.receivedData) _status.receivedData = false; //this line is incorrect !
return _status;
}
}
public class ExampleStatus
{
public int Id { get; set; }
public string Name { get; set; }
public bool receivedData { get; set; }
//I don't want to use this method
public void Clear()
{
Id = 0;
Name = string.Empty;
receivedData = false;
}
}
int stateType = 0;
void ContinuousLoop(ExampleStatus statusObj)
{
while (true)
{
//I don't want to use the options below
//statusObj.Clear();
//or
//statusObj = new ExampleStatus();
if (stateType == 0)
{
statusObj.Id = 0;
statusObj.Name = "Firs Status";
}
else if (stateType == 1)
{
statusObj.Id = 1;
statusObj.Name = "Second Status";
statusObj.receivedData = true;
}
else if (stateType == 2)
{
statusObj.Id = 2;
statusObj.Name = "Third Status";
}
}
}
void RunThread()
{
var t1 = new Thread(() =>
{
ContinuousLoop(status);
});
t1.Start();
}
Is it possible to set default values without a method or new instance, as shown in the example?
Actually that's why I'm asking this question:
I will use the class I have defined in many places. I will need to add a block of code, such as the Clear method, to every place I use it.
I'm also curious about one more thing. If I assign a new instance every time to reset my objects, does this cause problems in memory?
I know more or less how garbage collections work. However, they say that in practice it does not work as said in theory.
So if I add "IDisposable" to my Class, it would tell the garbage collector: Welcome, I'm a litter. Will you take me too?
I have created a simple list class from scratch. This is for a class assignment that I have been working on for about a week - very new to lists. We can not use generics so trying to research my question below has not been fruitful. Although I did get to watch 7 tutorials on youtube by BetterCoder and I found some stuff in my book but nothing with an example of "merging".
I have three classes - my node, my list, and my program. In my list class, I am working on building a Merge() method which eventually will compare the data in the two lists and merge them into an ordered list.
Right now for some reason my Merge method - which is very basic to help me understand what is happening - is not working correctly. It has both lists passed to it, and is adding the data from listTwo to listOne BUT for some reason when it's printing to the console the second Node's Data shows twice :
EX: 1 -> 2 -> 2
instead of printing the head (1), the next (2) and then the next (3) which it should be.
EX: 1 -> 2 -> 3
In the program class I have proven with a write line that (listOne.firstNode.Next.Next.Data) = 3 . Which it should be.
Can someone help me figure out if the nodes in list one aren't pointing to each other correctly or whatever is going on?
My Merge Method must be passed both list objects (listOne and listTwo) and eventually I need to make those passed as references but I haven't figured that out quite yet and will focus on that later I suppose.
namespace LinkedList
{
//This is my Node Class
class Node
{
public object Data { get; set; }
public Node Next { get; set; }
public Node(object dataValue) : this(dataValue, null) { }
public Node(object dataValue, Node nextNode)
{
Data = dataValue;
Next = nextNode;
}
}
//This is my List Class
class List
{
public Node firstNode;
public int count;
public List()
{
firstNode = null;
}
public bool Empty
{
get { return this.count == 0; }
}
public int Count
{
get { return this.count; }
}
public object Add(int index, object o)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (index > count)
index = count;
Node current = this.firstNode;
if (this.Empty || index == 0)
{
this.firstNode = new Node(o, this.firstNode);
}
else
{
for (int i = 0; i < index - 1; i++)
current = current.Next;
current.Next = new Node(o, current.Next);
}
count++;
return o;
}
public object Add(object o)
{
return this.Add(count, o);
}
public object Merge(List a, List b)
{
a.Add(b.firstNode.Data);
return a;
}
public void Print()
{
while (this.count > 0)
{
Console.Write(firstNode.Data + "->");
if(firstNode.Next != null)
firstNode.Data = firstNode.Next.Data;
count--;
}
}
}
//And here is my Program
class Program
{
static void Main(string[] args)
{
List listOne = new List();
List listTwo = new List();
listOne.Add(1);
listOne.Add(2);
listTwo.Add(3);
listTwo.Print();
Console.WriteLine("");
listOne.Merge(listOne, listTwo);
Console.WriteLine("");
listOne.Print();
//This line below shows that the data "3" from listTwo is being added to listOne in the list Merge Method
//Console.WriteLine(listOne.firstNode.Next.Next.Data);
Console.ReadKey();
}
}
}
Actual problem in your print method
public void Print()
{
Node node = firstNode;
for (int i = 0; i < this.count; i++)
{
Console.Write(node.Data + "->");
if (node.Next != null)
node = node.Next;
}
}
Alex Sikilinda , you are right the merge method is incomplete.
public object Merge(List a, List b)
{
Node bNode = b.firstNode;
while (bNode != null)
{
a.Add(bNode.Data);
bNode = bNode.Next;
}
return a;
}
I would write it this way:
public void Merge(List b)
{
Node lastNode = GetLastNode();
if (lastNode != null)
{
lastNode.Next = b.firstNode;
}
else
{
this.firstNode = b.firstNode;
}
}
// this method is used to find the last node in current list
private Node GetLastNode()
{
if (this.firstNode == null)
{
return null;
}
Node current = this.firstNode;
while (current.Next != null)
{
current = current.Next;
}
return current;
}
First of all, I changed signature of Merge from public object Merge(List a, List b) to public void Merge(List b). Now we can use it like this:
listOne.Merge(listTwo);
This will link listOne's last element with the first element of listTwo and thus they are merged.
Now we need to change Print method since current version modifies the list, which shouldn't happen:
public void Print()
{
Node currentNode = this.firstNode;
while(currentNode != null)
{
Console.Write(currentNode.Data + ' ');
currentNode = currentNode.Next;
}
}
Instead of assigning the data back to first node I assign the
firstNode = firstNode.Next;
Please check the below Print Code
public void Print()
{
while (this.count > 0)
{
Console.Write(firstNode.Data + "->");
if (firstNode.Next != null)
firstNode = firstNode.Next;
count--;
}
}
Can someone give me a code sample of 2-opt algorithm for traveling salesman problem. For now im using nearest neighbour to find the path but this method is far from perfect, and after some research i found 2-opt algorithm that would correct that path to the acceptable level. I found some sample apps but without source code.
So I got bored and wrote it. It looks like it works, but I haven't tested it very thoroughly. It assumes triangle inequality, all edges exist, that sort of thing. It works largely like the answer I outlined. It prints each iteration; the last one is the 2-optimized one.
I'm sure it can be improved in a zillion ways.
using System;
using System.Collections.Generic;
using System.Linq;
namespace TSP
{
internal static class Program
{
private static void Main(string[] args)
{
//create an initial tour out of nearest neighbors
var stops = Enumerable.Range(1, 10)
.Select(i => new Stop(new City(i)))
.NearestNeighbors()
.ToList();
//create next pointers between them
stops.Connect(true);
//wrap in a tour object
Tour startingTour = new Tour(stops);
//the actual algorithm
while (true)
{
Console.WriteLine(startingTour);
var newTour = startingTour.GenerateMutations()
.MinBy(tour => tour.Cost());
if (newTour.Cost() < startingTour.Cost()) startingTour = newTour;
else break;
}
Console.ReadLine();
}
private class City
{
private static Random rand = new Random();
public City(int cityName)
{
X = rand.NextDouble() * 100;
Y = rand.NextDouble() * 100;
CityName = cityName;
}
public double X { get; private set; }
public double Y { get; private set; }
public int CityName { get; private set; }
}
private class Stop
{
public Stop(City city)
{
City = city;
}
public Stop Next { get; set; }
public City City { get; set; }
public Stop Clone()
{
return new Stop(City);
}
public static double Distance(Stop first, Stop other)
{
return Math.Sqrt(
Math.Pow(first.City.X - other.City.X, 2) +
Math.Pow(first.City.Y - other.City.Y, 2));
}
//list of nodes, including this one, that we can get to
public IEnumerable<Stop> CanGetTo()
{
var current = this;
while (true)
{
yield return current;
current = current.Next;
if (current == this) break;
}
}
public override bool Equals(object obj)
{
return City == ((Stop)obj).City;
}
public override int GetHashCode()
{
return City.GetHashCode();
}
public override string ToString()
{
return City.CityName.ToString();
}
}
private class Tour
{
public Tour(IEnumerable<Stop> stops)
{
Anchor = stops.First();
}
//the set of tours we can make with 2-opt out of this one
public IEnumerable<Tour> GenerateMutations()
{
for (Stop stop = Anchor; stop.Next != Anchor; stop = stop.Next)
{
//skip the next one, since you can't swap with that
Stop current = stop.Next.Next;
while (current != Anchor)
{
yield return CloneWithSwap(stop.City, current.City);
current = current.Next;
}
}
}
public Stop Anchor { get; set; }
public Tour CloneWithSwap(City firstCity, City secondCity)
{
Stop firstFrom = null, secondFrom = null;
var stops = UnconnectedClones();
stops.Connect(true);
foreach (Stop stop in stops)
{
if (stop.City == firstCity) firstFrom = stop;
if (stop.City == secondCity) secondFrom = stop;
}
//the swap part
var firstTo = firstFrom.Next;
var secondTo = secondFrom.Next;
//reverse all of the links between the swaps
firstTo.CanGetTo()
.TakeWhile(stop => stop != secondTo)
.Reverse()
.Connect(false);
firstTo.Next = secondTo;
firstFrom.Next = secondFrom;
var tour = new Tour(stops);
return tour;
}
public IList<Stop> UnconnectedClones()
{
return Cycle().Select(stop => stop.Clone()).ToList();
}
public double Cost()
{
return Cycle().Aggregate(
0.0,
(sum, stop) =>
sum + Stop.Distance(stop, stop.Next));
}
private IEnumerable<Stop> Cycle()
{
return Anchor.CanGetTo();
}
public override string ToString()
{
string path = String.Join(
"->",
Cycle().Select(stop => stop.ToString()).ToArray());
return String.Format("Cost: {0}, Path:{1}", Cost(), path);
}
}
//take an ordered list of nodes and set their next properties
private static void Connect(this IEnumerable<Stop> stops, bool loop)
{
Stop prev = null, first = null;
foreach (var stop in stops)
{
if (first == null) first = stop;
if (prev != null) prev.Next = stop;
prev = stop;
}
if (loop)
{
prev.Next = first;
}
}
//T with the smallest func(T)
private static T MinBy<T, TComparable>(
this IEnumerable<T> xs,
Func<T, TComparable> func)
where TComparable : IComparable<TComparable>
{
return xs.DefaultIfEmpty().Aggregate(
(maxSoFar, elem) =>
func(elem).CompareTo(func(maxSoFar)) > 0 ? maxSoFar : elem);
}
//return an ordered nearest neighbor set
private static IEnumerable<Stop> NearestNeighbors(this IEnumerable<Stop> stops)
{
var stopsLeft = stops.ToList();
for (var stop = stopsLeft.First();
stop != null;
stop = stopsLeft.MinBy(s => Stop.Distance(stop, s)))
{
stopsLeft.Remove(stop);
yield return stop;
}
}
}
}
Well, your solution to TSP is always going to be far from perfect. No code, but here's how to go about 2-Opt. It's not too bad:
You need a class called Stop that has a Next, Prev, and City property, and probably a Stops property that just returns the array containing Next and Prev.
When you link them together, we'll call that a Tour. Tour has a Stop property (any of the stops will do), and an AllStops property, whose getter just walks the stops and returns them
You need a method that takes a tour and returns its cost. Let's call that Tour.Cost().
You need Tour.Clone(), which just walks the stops and clones them individually
You need a method that generates the set of tours with two edges switched. Call this Tour.PossibleMutations()
Start with your NN solution
Call PossibleMutations() on it
Call Cost() on all of them and take the one with the lowest result
Repeat until the cost doesn't go down
If the problem is euclidian distance and you want the cost of the solution produced by the algorithm is within 3/2 of the optimum then you want the Christofides algorithm. ACO and GA don't have a guaranteed cost.