Searching for all routes in a graph C# - c#

Hy guys!
I have a project where I need to find out if you can make gold from iron. The way it is is that each material is represented with a number from 1-200 and a catalisator which makes one material from an other with letters (A-Z). They experiment and store the records in a txt files. Each records looks like this: material1 catalisator material2. So this is basically a graph where every material is a vertex and every catalisator is an edge. The task is to read the txt files and create an other one with the necessary edges from iron(represented with 1) to gold(represented with 0). My current state is that I have a class called Beeolvaso:
class Beolvaso
{
public int anyag1;
public int anyag2;
public string katalizator;
public bool tovabbMehete;
public int Anyag1
{
get
{
return anyag1;
}
set
{
anyag1 = value;
}
}
public bool TovabbMehete
{
get
{
return tovabbMehete;
}
set
{
tovabbMehete = value;
}
}
public int Anyag2
{
get
{
return anyag2;
}
set
{
anyag2 = value;
}
}
public string Katalizator
{
get
{
return katalizator;
}
set
{
katalizator = value;
}
}
public Beolvaso(int anyag1, string katalizator, int anyag2, bool tovabbMehete)
{
this.anyag1 = anyag1;
this.anyag2 = anyag2;
this.katalizator = katalizator;
this.tovabbMehete = tovabbMehete;
}
it basiacally stores material1 material2 catalisator and a boolean which tells us if we can continoue from material2 to an other material or not.
I have an array containing serials of these Beolvaso classes I created that stores the data from the text in a structure and I need an algorithm that iterates through the records and return all the possible routes(serial of catalisators) from 1(iron) to 0(gold). I looked up different graph searches like DFS or BFS but I need an algorith specifically for that case. Can you guys help me out?

Related

Set a maximum count for parent-child object initialization c#

TL;DR ?:(
hi, I'm creating a source generator, It's been a pain since I started TBH.
I have a class:
public class CsharpTypeBase
{
public CsharpTypeBase(int childCount = 0)
{
childCount++;
if (childCount < 5)
{
Child = new(childCount);
}
}
public bool IsSimple { get; set; }
public bool IsArray { get; set; }
public bool IsIEnumerable { get; set; }
public ref CsharpTypeBase? Child
{
get => ref _child;
}
public string? ValueIfIsSimple
{
get => _valueIfIsSimple;
set
{
IsSimple = true;
_valueIfIsSimple = value;
}
}
public CsharpClassModel ClassModel
{
get => _classModel;
set
{
IsSimple = false;
_classModel = value;
}
}
private string? _valueIfIsSimple;
private CsharpClassModel _classModel = new();
private CsharpTypeBase? _child;
}
which is a base class for other CSharp types that I have(ex: ReturnTypes,Parameters,Properties)
with the following code im trying to parse c# classes into simpler versions(and after that do something with them):
public static CsharpTypeBase Convert(TypeSyntax typeSyntax)
{
var output = new CsharpTypeBase();
FromTypeSyntax(typeSyntax,ref output);
return output;
}
private static void FromTypeSyntax(TypeSyntax typeSyntax,ref CsharpTypeBase output)
{
switch (typeSyntax)
{
case PredefinedTypeSyntax predefinedTypeSyntax:
output.ValueIfIsSimple = predefinedTypeSyntax.Keyword.ValueText;
output.IsIEnumerable = false;
output.IsArray = false;
break;
case IdentifierNameSyntax identifierNameSyntax:
CsharpClassModel.RecursivelyWalkThroughTheClass(identifierNameSyntax.Identifier.ValueText,output);
break;
case ArrayTypeSyntax arrayTypeSyntax:
output.IsArray = true;
output.IsIEnumerable = false;
FromTypeSyntax(arrayTypeSyntax.ElementType,ref output.Child!);
break;
case GenericNameSyntax genericNameSyntax:
var (innerClass,isEnumerable) = FindTheMostInnerType(genericNameSyntax);
output.IsIEnumerable = isEnumerable;
FromTypeSyntax(innerClass,ref output.Child!);
break;
}
}
as you can see it's a recursive function, and its doing just fine, the only problem I have with this design is (that Child property) it's not really memory friendly and stable because of my base class, by default it's creating 5 child class(which is the same type as my base, it's stupid but I cant thing of anything else).
I want this to be more efficient, what if I only need 2 children? or worse, what if I needed more children to be created? I need the Exact Count otherwise it will OverFlow (by creating infinite objects) or blow up:
FromTypeSyntax(arrayTypeSyntax.ElementType,ref output.Child!);
this code should somehow set a maximum count for :
Child = new();
And the reason I need that Child property is to parse/convert this kind of incoming types:
List<string>[] one,
List<string[]> two,
Task<List<IReadOnlyCollection<FirstDto>>> three,
AnotherDto[] four,
string five,
int[] six,
List<List<List<List<List<List<string>>>>>> seven
Thank you for reading this question.
I solved My problem by making the Child object nullable:
public CsharpTypeBase? Child { get;set; }
and using it like this :
FromTypeSyntax(child, output.Child ??= new());

C# manipulating data parsed from CSV

I'm creating a program to generate schematics based off of user input. This has to be done dynamically/by hand due to the sheer volume of different possibilities (6.8M, growing exponentially). Right now I'm working on importing some data via CSV.
Example data:
Type,TIN_pos,TIN_ID,Desc
Elect, 0, X, Manual Regulator
Elect, 0, A, Electronic Regulator
Import code:
List<TIN_Fields> values = File.ReadAllLines("C:\\Users\\User\\Desktop\\Visual Basic\\CSV_Test_1.csv")
.Skip(1)
.Select(v => TIN_Fields.FromCsv(v))
.ToList();
public class TIN_Fields
{
public string Type;
public int TIN_pos;
public string TIN_ID;
public string Desc;
public static TIN_Fields FromCsv(string csvLine)
{
string[] values = csvLine.Split(',');
TIN_Fields _Fields = new TIN_Fields();
_Fields.Type = Convert.ToString(values[0]);
_Fields.TIN_pos = Convert.ToInt16(values[1]);
_Fields.TIN_ID = Convert.ToString(values[2]);
_Fields.Desc = Convert.ToString(values[3]);
return _Fields;
}
}
Once that data is Imported, I need to do two things with it,
display the raw csv data in a ListView table, just so users can see if anything in the list needs updating.
be able to compare the items in the list to various characters in a 10-digit hexadecimal code, and spit out some results.
First and foremost, i need to run through the list that was created with the above code, make sure that:
TIN_pos value = 0
because that is the character position of the input box.
Then, with the remaining options, look for the character represented in the input in the TIN_ID field.
Once found, it should then output the Desc field.
Everywhere I have looked says to use foreach, but that requires the array name, which is the part that is confusing me. I've tried filling in basically all of the variables in the FromCSV Method and usually get an error that the class doesn't have a definition.
to hopefully clear up confusion with my explanation, here is the code I created that does the same thing, but with the CSV data hard coded into it, using switch cases and if statements.
public partial class Form1 : Form
{
public string Model_Chassis;
public string Model_Test_Type;
public int ChannelNumberVar => Convert.ToInt32(TextBox_TIN[2]);
public string Tester_Type_Selector;
public string TextBox_TIN
{
get { return TIN_Entry_TextBox.Text; }
set { TIN_Entry_TextBox.Text = value; }
}
public string Model_Data_D
{
get { return Model_Data.Text; }
set { Model_Data.Text = value; }
}
public Form1()
{
InitializeComponent();
}
//Method grabs TIN Box data and decodes it to model information.
public void Model_Select()
{
//Picks Model Chassis
switch (char.ToUpper(TextBox_TIN[0]))
{
case 'H':
{
Model_Chassis = Coding.Model1.description;
}
break;
default:
{
Model_Data_D = "INVALID TIN";
}
break;
}
//Picks Test Type
switch (char.ToUpper(TextBox_TIN[3]))
{
case '0':
{
Model_Test_Type = Test_Types.TT_PD.TT_tt;
}
break;
case '1':
{
Model_Test_Type = Test_Types.TT_PV.TT_tt;
}
break;
default:
{
Model_Test_Type = "";
}
break;
}
//Puts chassis and Test Type together
if (Model_Data_D.Equals("INVALID TIN"))
{
;
}
else if (char.ToUpper(TextBox_TIN[2]).Equals(Coding.Num_Chan_1_2.tin_id))
{
Model_Data_D = $"{Model_Chassis}-{Model_Test_Type}";
}
else
{
Model_Data_D = $"{Model_Chassis}-{TextBox_TIN[2]}{Model_Test_Type}";
}
}
public class Coding
{
public char tin_id;
public string description;
public Coding(char TIN_ID, string Desc)
{
tin_id = TIN_ID;
description = Desc;
}
public static Coding Model1 = new Coding('H', "Model1");
public static Coding Num_Chan_1_2 = new Coding('X', "Single Channel");
public static Coding Elect_Reg_F_1 = new Coding('X', "Manual Regulator");
}
}
INPUT:
HXX0X
OUTPUT
Model1-PD
Thanks in advance for the help!
You're asking quite a few questions, and providing a lot of extra details in here, but for this:
"First and foremost, i need to run through the list that was created with the above code, make sure that:
TIN_pos value = 0
because that is the character position of the input box."
(seeing as you say you need to do this 'first and foremost').
In your FromCsv method, check the value as you create the record, and throw an error if it is invalid. Like this:
public static TIN_Fields FromCsv(string csvLine)
{
string[] values = csvLine.Split(',');
TIN_Fields _Fields = new TIN_Fields();
_Fields.Type = Convert.ToString(values[0]);
_Fields.TIN_pos = Convert.ToInt16(values[1]);
if(_Fields.TIN_pos != 0){
throw new Exception("TIN_pos must be 0");
}
_Fields.TIN_ID = Convert.ToString(values[2]);
_Fields.Desc = Convert.ToString(values[3]);
return _Fields;
}
Assuming you've read in your CSV correctly, which it seems you have, then selecting the appropriate TIN from the list is a simple LINQ statement. The following code assumes that TIN IDs are unique and only a single character in length.
static void Main(string[] args)
{
string testCsv = #"C:\Users\User\Desktop\Visual Basic\CSV_Test_1.csv";
List<TIN_Fields> values = File.ReadAllLines(testCsv)
.Skip(1)
.Select(v => TIN_Fields.FromCsv(v))
.ToList();
// Simulates input received from form
string input = "HXX0X";
TIN_Fields selectedTIN = values.First(x => x.TIN_ID == Convert.ToString(input[0]));
// Insert the description as needed in your ouput.
string output = $"{ selectedTIN.Desc }-";
}
Hopefully that answers another part of the problem. The Convert.ToString() is required because the output of input[0] is a char.

c# GroupPrincipal.FindByIdentity finds the group, but when using GetMembers getting error - there is no such object on the server

this code used to work fine for the past year,
now it is still working, but i have only 4 groups that generate this error...
the code is simple:
using (var context = new PrincipalContext(ContextType.Domain, domName))
{
foreach (string grp in myGroups)
{
using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, grp))
{
PrincipalSearchResult<Principal> usersList;
usersList = group.GetMembers(true);
int usersListCount = usersList.Count();
}}}
when these specific groups come to search , i get the group and can see its description in the group object variable, but when getting its members i get an error massage :
base: "There is no such object on the server.\r\n"
ErrorCode: -2147016656
again,this happens only with 4 specific groups from the same domain, and same OU.
this just started a few days ago without me changing anything, not permissions, nothing in the code, very strange...
any ideas ?
When I encountered this problem I could not have an empty group. I had to produce "best possible" results while the network people were working to resolve the "foreign SID" issue.
I know it is a lot extra but it satisfied the auditors so maybe it will help you. This is what I did:
Precursor: I had already built a class that held all the properties of the AD Entity.
Got a list of users and all their group memberships.
Wrapped the call to get members in a try... catch and when this error occurred I inserted a "Group Membership" property of "Error Retrieving members"
When I had iterated through all the Groups I grabbed a list of all groups that had the error message as a group member then queried the Users list to get a list of all the users who were members of that group.
Then inserted Property records with the found users names.
Since this answer is more about solution structure I will only give a very brief outline of the classes used. While far from elegant it gave me a reusable container that was easy to understand and share and provided a solution that was durable across several networks. It probably lacks in many ways but it passes test #1 - it worked.
public class ADPropEntry : IComparable<ADPropEntry>
{
#region Properties
public string Name { get { return _name; } set { _adName = value; SetPropVals(_adName); } }
public string Value { get { return _v; } set { _v = value; DoValConversion(); } }
public bool IsVisible { get { return _isVis; } set { _isVis = value; } }
public string ConvertTo { get { return _convertVal; } set { _convertVal = value; } }
public int ID { get { return _id; } set { _id = value; } }
#endregion
private void SetPropVals(string s)
{
switch (s)
{
case "accountexpires": _name = "Account Expires"; _isVis = false; _convertVal = "FromFileTime"; break;
... more handles each property conversion
}
}
}
public class ADEntity : IComparable<ADEntity>
{
#region Properties
public string Name { get { return _name; } set { _name = value; } }
public List<ADPropEntry> MyProperty { get { return _ade; } set { _ade = value; } }
public string EntityType { get { return _entT; } set { _entT = value; } }
public string ADName { get { return GetProperty("SAM Account Name"); } }
#endregion
}
This formed provided me a durable data container and then I used another class to query AD in whatever method makes sense. This was packaged in a DLL that the client application could use.
class ADAccess
{
#region Properties
public bool HasErrors { get { return (bool)(_errMsg.Length > 10); } }
public string ErrorMsg { get { return _errMsg; } }
public List<ADEntity> GroupEntries { get { return _lstGrps; } }
public List<ADEntity> UserEntries { get { return _lstUsrs; } }
public List<ADEntity> PrinterEntries { get { return _lstPrts; } }
public List<ADEntity> ComputerEntries { get { return _lstCmps; } }
#endregion
public List<ADEntity> GetADListByMSO(string groupType)
{
if (groupType == "")
{
// get them all return an empty list populating properties
}
else
{
// set the context and fetch return populated list
}
}
Used the same structure to report on SQL server permissions as well.
i found out the issue,
the problematic groups contained users from different domains,
once removed these users from the groups , everything went back to work.
thanks.

How to filter a class by picking out a specific DateTime value?

EDIT: Everything that I had problems with was solved in the comments :)
Before we get into things, I'm very new to programming with c#, only had very brief experience with c++. So I'm very sorry if I get some terminology wrong, they are all still confusing to me and I always mix them up.
Alright, so I have a list of basketball players in a separate .csv file. Here's the class for them:
//Renaldas Seibutis;196;AG;Kauno „Žalgiris“;1985-07-23;TRUE;FALSE; <- example of player's data in the .csv file
namespace Lab1
{
class PlayerList
{
public string FullName { get; set; }
public int Height { get; set; }
public string Position { get; set; }
public string Club { get; set; }
public DateTime BirthdayDate { get; set; }
public bool IsInvited { get; set; }
public bool IsCaptain { get; set; }
public PlayerList()
{
}
public PlayerList(string fullName, int height, string position, string club, DateTime birthdayDate, bool isInvited, bool isCaptain)
{
FullName = fullName;
Height = height;
Position = position;
Club = club;
BirthdayDate = birthdayDate;
IsInvited = isInvited;
IsCaptain = isCaptain;
}
}
}
And here is my Main() part of the program:
static void Main(string[] args)
{
List<PlayerList> players = ReadData();
players = ReadData();
PrintDataToConsole(players);
List<PlayerList> filteredByClub = FilterByClub(players);
PrintFilteredByClub(players, filteredByClub);
List<PlayerList> youngestPlayer = FindYoungestPlayer(players);
Console.ReadKey();
}
The FilterByClub method below, finds all players who are in that particular club and adds it to a new filteredByClub List and the filtered list gets printed on console. I found a similar algorithm somewhere on stackoverflow and applied it to my case to write this method.
private static List<PlayerList> FilterByClub(List<PlayerList> players)
{
return players.FindAll(o => o.Club.Equals("Kauno „Žalgiris“")).ToList();
}
What I'm having troubles with is making another method to filter the youngest player by finding a player with the biggest DateTime value in "class PlayerList" and then adding that player to the new list so then I could pass that new list over to a method that prints it on the console, similarly how I filtered the players with FilterByClub and PrintFilteredByClub methods. There might be a way to return that single youngest player only with making a new List, but I can't even begin to imagine the syntax for that.
I've tried for cycle, foreach, if statements e.t.c, I just can't seem to figure out how to use DateTime value correctly, I keep getting errors that they can't be used as bool or int values and similar mistakes. Is there some special algorithm or syntax that lets you find maximum or minimum value of DateTime from a list of many DateTime values?
private static PlayerList FindYoungest(List<PlayerList> players)
{
return players.OrderByDescending(o => o.BirthdayDate).FirstOrDefault();
}
I hope that helps. It will return a single player (the youngest). Also, I recommend you to change the name of your class to Player instead of PlayerList.

List/Collection of references to Properties

Consider these properties,
double _temperature;
public double Temperature
{
get { return _temperature; }
set { _temperature = value; }
}
double _humidity;
public double Humidity
{
get { return _humidity; }
set { _humidity = value; }
}
bool _isRaining;
public bool IsRaining
{
get { return _isRaining; }
set { _isRaining = value; }
}
And now I want to make a list/collection/container of properties like this,
PropertyContainer.Add(Temperature); //Line1
PropertyContainer.Add(Humidity); //Line2
PropertyContainer.Add(IsRaining); //Line3
I want to make this such that later on I may be able to access the current values of properties using index, something like this,
object currentTemperature = PropertyContainer[0];
object currentHumidity = PropertyContainer[1];
object currentIsRaining = PropertyContainer[2];
But obviously, this is not going to work, since PropertyContainer[0] will return the old value - the value which Temperature had at the time of adding Temperature to the container (see the Line1 above).
Is there any solution to this problem? Basically I want to access current values of properties uniformly; the only thing that can change is, the index. The index however could be string as well.
PS: I don't want to use Reflection!
Well, you could use Lambdas:
List<Func<object>> PropertyAccessors = new List<Func<object>>();
PropertyAccessors.Add(() => this.Temperature);
PropertyAccessors.Add(() => this.Humidity);
PropertyAccessors.Add(() => this.IsRaining);
then you could to this:
object currentTemperature = PropertyAccessors[0]();

Categories