How can make my URL checker program faster? - c#

I made a URL checker program which is checked URLs from a list and return valid sub links recursively. It checks all sub links. I have more than 100 main page like this and I would check these sites with all subs. It takes 3 minutes averagely for one site. especially first Html Code (at the sample string "HtmlCode = client.DownloadString(Link);") takes times, the others faster than first. I would run my program repeatedly and it control links and sending me warning for broken links. How could I faster my program?
public Form1()
{
InitializeComponent();
List<KeyValuePair<string, bool>> UrlS = Link_Bul_v2("http://www.asdfhg.com", new List<string>(), new List<KeyValuePair<string, bool>>());
List<KeyValuePair<string, bool>> UrlS2 = Link_Bul_v2("http://www.huuene.com", new List<string>(), new List<KeyValuePair<string, bool>>());
}
string UrlSadelesti(string Link)
{
return Link.Replace("https://", "").Replace("http://", "").Replace("www.", "");
}
WebClient client = new WebClient();
private List<KeyValuePair<string, bool>> Link_Bul_v2(string Link, List<string> HList, List<KeyValuePair<string, bool>> CList)
{
try
{
string HtmlCode = client.DownloadString(Link);
//if(HtmlCode.
CList.Add(new KeyValuePair<string, bool>(Link, true));
var Link_Short = UrlSadelesti(Link).Split('/')[0];
//HList.Add(Link_Short);
string DLink;
int IndexH = 0;
while (true)
{
IndexH = HtmlCode.IndexOf("href", IndexH);
if (IndexH == -1) { break; }
if (HtmlCode[IndexH - 1] == '.')
{
IndexH = IndexH + 1;
}
else
{
var IndexD1 = HtmlCode.IndexOf('"', IndexH);
var IndexD2 = HtmlCode.IndexOf('"', IndexD1 + 1);
var length = IndexD2 - (IndexD1 + 1);
DLink = HtmlCode.Substring(IndexD1 + 1, length);
IndexH = IndexD2;
if ((DLink.Contains(".css") == false))
{
if (DLink.Contains("http://") || DLink.Contains("https://"))
{
if (DLink.Contains(Link_Short) == false)
continue;
}
if (DLink.Contains("#"))
{
continue;
}
DLink = UrlSadelesti(DLink).Replace(Link_Short, "");
if (DLink.Length == 1)
continue;
if (HList.Count(p => p.Contains(DLink)) == 0)
{
if (DLink.Contains("http://") || DLink.Contains("https://"))
{
HList.Add(Link_Short + "/" + DLink);
}
else
{
HList.Add("http://" + Link_Short + "/" + DLink);
}
}
}
}
}
}
catch
{
CList.Add(new KeyValuePair<string, bool>(Link, false));
if (!HList.Contains(Link))
HList.Add(Link);
if (UrlSadelesti(Link).Split('/').Count() > 1)
{
Link_Bul_v2("http://" + UrlSadelesti(Link).Split('/')[0], HList, CList);
}
}
foreach (string s in HList)
{
if (CList.Count(p => p.Key.Contains(s)) == 0)
{
Link_Bul_v2(s, HList, CList);
}
}
return CList;
}

One option would be to check each link in parallel:
How to: Write a Simple Parallel.ForEach Loop
using System.Threading;
using System.Threading.Tasks;
...
Parallel.ForEach(links, (currentLink) =>
{
// Check "currentLink"
});
// All links are checked at this point

Related

Group list of strings by subparts of item

Sorry for the ambiguous title...
I find explaining my issue difficult - let me know if you need to know more.
I've got a list that i'd like to be grouped by part of a string.
This string is also in the list.
This is the complete list, its not static, and will contain different values.
CookieMaker_TransportSettingsManual
CookieMaker_TransportSettingsParameters
Cookie_WrapperSettings
Cookie_WrapperSettingsManual
Cookie_WrapperSettingsParameters
Cookie_ProfileBendSettings
Cookie_ProfileBendSettingsParameters
Cookie_HopperSettings
Cookie_HopperSettingsManual
Cookie_HopperSettingsParameters
Cookie_CutterSettings
Cookie_CutterSettingsManual
Cookie_CutterSettingsParameters
General_SpeedSetting
General_SpeedSettingManual
General_SpeedSettingSettings
General_CalibrationSettings
General_CalibrationSettingsCalibration
Bonbon_Vertical
Bonbon_VerticalAligner
Bonbon_VerticalHopper
Bonbon_VerticalManual
Bonbon_VerticalTransporter
Bonbon_Horizontal
Bonbon_HorizontalHopper
Bonbon_HorizontalManual
Bonbon_HorizontalCookie
Bonbon_HorizontalTransporter
Bonbon_Bonbon
Bonbon_BonbonExhaust
Bonbon_BonbonManual
Bonbon_BonbonSection1
Bonbon_BonbonSection2
Bonbon_BonbonSection3
Bonbon_Compensator
Bonbon_CompensatorCarriage
Bonbon_CompensatorHopper
Bonbon_CompensatorManual
Bonbon_CollectingUnit
Bonbon_CollectingUnitManual
Bonbon_CollectingUnitTransporter
Bonbon_CollectingUnitTubeMaker
CookieMaker_TransportSettings
CookieMaker_TransportSettingsBonbon
CookieMaker_TransportSettingsPandora
The expected result would be a groups like so:
General_SpeedSetting
==> General_SpeedSettingManual
==> General_SpeedSettingSettings
Cookie_WrapperSettings
==> Cookie_WrapperSettingsManual
==> Cookie_WrapperSettingsParameters
The resulting datatype does not matter.
Also i don't mind linq.
Code / fiddle to get up and running quickly;
using System;
public class Program
{
public static void Main()
{
var inputString = "CookieMaker_TransportSettingsManual|CookieMaker_TransportSettingsParameters|Cookie_WrapperSettings|Cookie_WrapperSettingsManual|Cookie_WrapperSettingsParameters|Cookie_ProfileBendSettings|Cookie_ProfileBendSettingsParameters|Cookie_HopperSettings|Cookie_HopperSettingsManual|Cookie_HopperSettingsParameters|Cookie_CutterSettings|Cookie_CutterSettingsManual|Cookie_CutterSettingsParameters|General_SpeedSetting|General_SpeedSettingManual|General_SpeedSettingSettings|General_CalibrationSettings|General_CalibrationSettingsCalibration|Bonbon_Vertical|Bonbon_VerticalAligner|Bonbon_VerticalHopper|Bonbon_VerticalManual|Bonbon_VerticalTransporter|Bonbon_Horizontal|Bonbon_HorizontalHopper|Bonbon_HorizontalManual|Bonbon_HorizontalCookie|Bonbon_HorizontalTransporter|Bonbon_Bonbon|Bonbon_BonbonExhaust|Bonbon_BonbonManual|Bonbon_BonbonSection1|Bonbon_BonbonSection2|Bonbon_BonbonSection3|Bonbon_Compensator|Bonbon_CompensatorCarriage|Bonbon_CompensatorHopper|Bonbon_CompensatorManual|Bonbon_CollectingUnit|Bonbon_CollectingUnitManual|Bonbon_CollectingUnitTransporter|Bonbon_CollectingUnitTubeMaker|CookieMaker_TransportSettings|CookieMaker_TransportSettingsBonbon|CookieMaker_TransportSettingsPandora";
var inputList = inputString.Split('|');
var result = inputList; // Code here ;)
foreach(var r in result)
{ Console.WriteLine(r);}
}
}
https://dotnetfiddle.net/neCUEL
What about something like this?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static List<string> myList = new List<string>(){
"CookieMaker_TransportSettingsManual",
"CookieMaker_TransportSettingsParameters",
"Cookie_WrapperSettings",
"Cookie_WrapperSettingsManual",
"Cookie_WrapperSettingsParameters",
"Cookie_ProfileBendSettings",
"Cookie_ProfileBendSettingsParameters",
"Cookie_HopperSettings",
"Cookie_HopperSettingsManual",
"Cookie_HopperSettingsParameters",
"Cookie_CutterSettings",
"Cookie_CutterSettingsManual",
"Cookie_CutterSettingsParameters",
"General_SpeedSetting",
"General_SpeedSettingManual",
"General_SpeedSettingSettings",
"General_CalibrationSettings",
"General_CalibrationSettingsCalibration",
"Bonbon_Vertical",
"Bonbon_VerticalAligner",
"Bonbon_VerticalHopper",
"Bonbon_VerticalManual",
"Bonbon_VerticalTransporter",
"Bonbon_Horizontal",
"Bonbon_HorizontalHopper",
"Bonbon_HorizontalManual",
"Bonbon_HorizontalCookie",
"Bonbon_HorizontalTransporter",
"Bonbon_Bonbon",
"Bonbon_BonbonExhaust",
"Bonbon_BonbonManual",
"Bonbon_BonbonSection1",
"Bonbon_BonbonSection2",
"Bonbon_BonbonSection3",
"Bonbon_Compensator",
"Bonbon_CompensatorCarriage",
"Bonbon_CompensatorHopper",
"Bonbon_CompensatorManual",
"Bonbon_CollectingUnit",
"Bonbon_CollectingUnitManual",
"Bonbon_CollectingUnitTransporter",
"Bonbon_CollectingUnitTubeMaker",
"CookieMaker_TransportSettings",
"CookieMaker_TransportSettingsBonbon",
"CookieMaker_TransportSettingsPandora"
};
static Dictionary<string, List<string>> results = new Dictionary<string, List<string>>();
//-------------------------------------------------------------------------//
public static void Main()
{
var orderedList = myList.OrderBy(i=>i).ToList();
int i = 0;
while(i < myList.Count){
var prefix = orderedList[i];
results[prefix] = new List<string>();
if(++i >= orderedList.Count) break;
while(orderedList[i].StartsWith(prefix)){
results[prefix].Add(orderedList[i]);
i++;
if(i >= orderedList.Count) {
Print();
return;
}
}//while
}//while
Print();
}//main
//-------------------------------------------------------------------------//
private static void Print(){
foreach (string prefix in results.Keys)
{
Console.WriteLine($"Prefix =>{prefix} - {results[prefix].Count}");
foreach (string result in results[prefix])
{
Console.WriteLine($" ======>{result}");
}//foreach;
}//foreach
}//Print
}//Cls
Fiddle:
https://dotnetfiddle.net/GTI4vV
I'm surprised you accepted a solution that pre-sorted the items. When I tried that, the Bonbon sections got terribly messed up.
My solution is a bit hacky - to get this to work the way I think you want it took a lot of special cases (and fixing off-by-one issues).
The code takes care of this kind of pattern:
CookieMaker_TransportSettingsManual
CookieMaker_TransportSettingsParameters
extracting CookieMaker_TransportSettings and putting both entries under it. It also copes with the fact that you have CookieMaker_TransportSettings at the beginning and the end of the file.
It also handles this:
Bonbon_BonbonSection1
Bonbon_BonbonSection2
Bonbon_BonbonSection3
Figuring that you want the three of those to be part of the Bonbon_Bonbon section and not a new Bonbon_BonbonSection section with three entries (1, 2 and 3).
It also deals with all the Cookie** and Bonbon** sections.
Here's the main code:
//get all the strings from somewhere
var inputStrings = File.ReadAllLines("DataFile.txt");
string lastTitle = null;
var results = new Dictionary<string, List<string>>();
string veryLastItem = string.Empty;
var currentItems = new List<string>();
for (var i = 0; i < inputStrings.Length - 1; ++i)
{
var commonPrefix = FindLongestCommonPrefix(inputStrings[i], inputStrings[i + 1]);
if (string.IsNullOrEmpty(commonPrefix) || (!string.IsNullOrEmpty(lastTitle) && commonPrefix != lastTitle))
{
if (string.IsNullOrEmpty(lastTitle))
{
throw new Exception("This isn't going to work - you need to have at least two common things in a row");
}
if (inputStrings[i].StartsWith(lastTitle) && inputStrings[i] != lastTitle)
{
currentItems.Add(inputStrings[i]);
}
AddResultsToDictionary(results, lastTitle, currentItems);
currentItems = new List<string>();
}
if (commonPrefix != inputStrings[i] &&
((commonPrefix == lastTitle && commonPrefix != inputStrings[i]) ||
(!string.IsNullOrEmpty(commonPrefix) && inputStrings[i].StartsWith(commonPrefix))))
{
currentItems.Add(inputStrings[i]);
}
lastTitle = commonPrefix;
veryLastItem = inputStrings[i + 1];
}
//ok, we're out of the loop:
//add the last item to the current list
currentItems.Add(veryLastItem);
//and add the last set of items to the dictionary
if (lastTitle != null)
{
AddResultsToDictionary(results, lastTitle, currentItems);
}
foreach (var result in results)
{
Debug.WriteLine(result.Key);
foreach (var item in result.Value)
{
Debug.WriteLine($" ==> {item}");
}
}
void AddResultsToDictionary(Dictionary<string, List<string>> dictionary, string s, List<string> list)
{
if (dictionary.TryGetValue(s, out var existingList))
{
existingList.AddRange(list);
}
else
{
dictionary.Add(s, list);
}
}
}
And it calls this function to determine the section headings:
private string FindLongestCommonPrefix(string s1, string s2)
{
var minLen = Math.Min(s1.Length, s2.Length);
for (var i = 0; i < minLen; ++i)
{
if (s1[i] != s2[i])
{
if (i == 0)
{
return string.Empty;
}
else
{
//if the common part is not s1, we need to find the last place where the following
// the last letter of the common part is a lower case letter followed by either
// an underscore or a capital letter
if (i == s1.Length)
{
return s1;
}
if (s1[i] == '_' || s1[i - 1] == '_' || s2[i] == '_' || s2[i - 1] == '_')
{
return string.Empty;
}
for (var j = i; j > 0; --j)
{
if (char.IsLower(s1[j-1]) && (char.IsUpper(s1[j]) /*|| s1[j] == '_'*/))
{
return s1.Substring(0, j);
}
}
//I shouldn't get here, but, if I do
return string.Empty;
}
}
}
//otherwise
return s1.Substring(0, minLen);
}
The result ends up looking like:
CookieMaker_TransportSettings
==> CookieMaker_TransportSettingsManual
==> CookieMaker_TransportSettingsParameters
==> CookieMaker_TransportSettingsBonbon
==> CookieMaker_TransportSettingsPandora
Cookie_WrapperSettings
==> Cookie_WrapperSettingsManual
==> Cookie_WrapperSettingsParameters
Cookie_ProfileBendSettings
==> Cookie_ProfileBendSettingsParameters
Cookie_HopperSettings
==> Cookie_HopperSettingsManual
==> Cookie_HopperSettingsParameters
Cookie_CutterSettings
==> Cookie_CutterSettingsManual
==> Cookie_CutterSettingsParameters
General_SpeedSetting
==> General_SpeedSettingManual
==> General_SpeedSettingSettings
General_CalibrationSettings
==> General_CalibrationSettingsCalibration
Bonbon_Vertical
==> Bonbon_VerticalAligner
==> Bonbon_VerticalHopper
==> Bonbon_VerticalManual
==> Bonbon_VerticalTransporter
Bonbon_Horizontal
==> Bonbon_HorizontalHopper
==> Bonbon_HorizontalManual
==> Bonbon_HorizontalCookie
==> Bonbon_HorizontalTransporter
Bonbon_Bonbon
==> Bonbon_BonbonExhaust
==> Bonbon_BonbonManual
==> Bonbon_BonbonSection1
==> Bonbon_BonbonSection2
==> Bonbon_BonbonSection3
Bonbon_Compensator
==> Bonbon_CompensatorCarriage
==> Bonbon_CompensatorHopper
==> Bonbon_CompensatorManual
Bonbon_CollectingUnit
==> Bonbon_CollectingUnitManual
==> Bonbon_CollectingUnitTransporter
==> Bonbon_CollectingUnitTubeMaker
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
List<string> lines = File.ReadLines(FILENAME).ToList();
lines = lines.OrderBy(x => x).ToList();
List<Group> groups = new List<Group>();
Group group = new Group();
groups.Add(group);
group.basename = lines[0].Trim();
List<List<string>> results = new List<List<string>>();
for (int i = 2; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (!line.StartsWith(group.basename))
{
group = new Group();
groups.Add(group);
group.basename = line;
}
else
{
if(group.values == null) group.values = new List<string>();
group.values.Add(line.Substring(group.basename.Length));
}
}
}
}
public class Group
{
public string basename { get; set; }
public List<string> values { get; set; }
}
}

How to parse nested parenthesis only in first level in C#

I would like to write C# code that parses nested parenthesis to array elements, but only on first level. An example is needed for sure:
I want this string:
"(example (to (parsing nested paren) but) (first lvl only))"
tp be parsed into:
["example", "(to (parsing nested paren) but)", "(first lvl only)"]
I was thinking about using regex but can't figure out how to properly use them without implementing this behaviour from scratch.
In the case of malformed inputs I would like to return an empty array, or an array ["error"]
I developed a parser for your example. I also checked some other examples which you can see in the code.
using System;
using System.Collections;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string str = "(example (to (parsing nested paren) but) (first lvl only))"; // => [example , (to (parsing nested paren) but) , (first lvl only)]
//string str = "(first)(second)(third)"; // => [first , second , third]
//string str = "(first(second)third)"; // => [first , (second) , third]
//string str = "(first(second)(third)fourth)"; // => [first , (second) , (third) , fourth]
//string str = "(first((second)(third))fourth)"; // => [first , ((second)(third)) , fourth]
//string str = "just Text"; // => [ERROR]
//string str = "start with Text (first , second)"; // => [ERROR]
//string str = "(first , second) end with text"; // => [ERROR]
//string str = ""; // => [ERROR]
//string str = "("; // => [ERROR]
//string str = "(first()(second)(third))fourth)"; // => [ERROR]
//string str = "(((extra close pareanthese))))"; // => [ERROR]
var res = Parser.parse(str);
showRes(res);
}
static void showRes(ArrayList res)
{
var strings = res.ToArray();
var theString = string.Join(" , ", strings);
Console.WriteLine("[" + theString + "]");
}
}
public class Parser
{
static Dictionary<TokenType, TokenType> getRules()
{
var rules = new Dictionary<TokenType, TokenType>();
rules.Add(TokenType.OPEN_PARENTHESE, TokenType.START | TokenType.OPEN_PARENTHESE | TokenType.CLOSE_PARENTHESE | TokenType.SIMPLE_TEXT);
rules.Add(TokenType.CLOSE_PARENTHESE, TokenType.SIMPLE_TEXT | TokenType.CLOSE_PARENTHESE);
rules.Add(TokenType.SIMPLE_TEXT, TokenType.SIMPLE_TEXT | TokenType.CLOSE_PARENTHESE | TokenType.OPEN_PARENTHESE);
rules.Add(TokenType.END, TokenType.CLOSE_PARENTHESE);
return rules;
}
static bool isValid(Token prev, Token cur)
{
var rules = Parser.getRules();
return rules.ContainsKey(cur.type) && ((prev.type & rules[cur.type]) == prev.type);
}
public static ArrayList parse(string sourceText)
{
ArrayList result = new ArrayList();
int openParenthesesCount = 0;
Lexer lexer = new Lexer(sourceText);
Token prevToken = lexer.getStartToken();
Token currentToken = lexer.readNextToken();
string tmpText = "";
while (currentToken.type != TokenType.END)
{
if (currentToken.type == TokenType.OPEN_PARENTHESE)
{
openParenthesesCount++;
if (openParenthesesCount > 1)
{
tmpText += currentToken.token;
}
}
else if (currentToken.type == TokenType.CLOSE_PARENTHESE)
{
openParenthesesCount--;
if (openParenthesesCount < 0)
{
return Parser.Error();
}
if (openParenthesesCount > 0)
{
tmpText += currentToken.token;
}
}
else if (currentToken.type == TokenType.SIMPLE_TEXT)
{
tmpText += currentToken.token;
}
if (!Parser.isValid(prevToken, currentToken))
{
return Parser.Error();
}
if (openParenthesesCount == 1 && tmpText.Trim() != "")
{
result.Add(tmpText);
tmpText = "";
}
prevToken = currentToken;
currentToken = lexer.readNextToken();
}
if (openParenthesesCount != 0)
{
return Parser.Error();
}
if (!Parser.isValid(prevToken, currentToken))
{
return Parser.Error();
}
if (tmpText.Trim() != "")
{
result.Add(tmpText);
}
return result;
}
static ArrayList Error()
{
var er = new ArrayList();
er.Add("ERROR");
return er;
}
}
class Lexer
{
string _txt;
int _index;
public Lexer(string text)
{
this._index = 0;
this._txt = text;
}
public Token getStartToken()
{
return new Token(-1, TokenType.START, "");
}
public Token readNextToken()
{
if (this._index >= this._txt.Length)
{
return new Token(-1, TokenType.END, "");
}
Token t = null;
string txt = "";
if (this._txt[this._index] == '(')
{
txt = "(";
t = new Token(this._index, TokenType.OPEN_PARENTHESE, txt);
}
else if (this._txt[this._index] == ')')
{
txt = ")";
t = new Token(this._index, TokenType.CLOSE_PARENTHESE, txt);
}
else
{
txt = this._readText();
t = new Token(this._index, TokenType.SIMPLE_TEXT, txt);
}
this._index += txt.Length;
return t;
}
private string _readText()
{
string txt = "";
int i = this._index;
while (i < this._txt.Length && this._txt[i] != '(' && this._txt[i] != ')')
{
txt = txt + this._txt[i];
i++;
}
return txt;
}
}
class Token
{
public int position
{
get;
private set;
}
public TokenType type
{
get;
private set;
}
public string token
{
get;
private set;
}
public Token(int position, TokenType type, string token)
{
this.position = position;
this.type = type;
this.token = token;
}
}
[Flags]
enum TokenType
{
START = 1,
OPEN_PARENTHESE = 2,
SIMPLE_TEXT = 4,
CLOSE_PARENTHESE = 8,
END = 16
}
well, regex will do the job:
var text = #"(example (to (parsing nested paren) but) (first lvl only))";
var pattern = #"\(([\w\s]+) (\([\w\s]+ \([\w\s]+\) [\w\s]+\)) (\([\w\s]+\))\)*";
try
{
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
Match m = r.Match(text);
string group_1 = m.Groups[1].Value; //example
string group_2 = m.Groups[2].Value; //(to (parsing nested paren) but)
string group_3 = m.Groups[3].Value; //(first lvl only)
return new string[]{group_1,group_2,group_3};
}
catch(Exception ex){
return new string[]{"error"};
}
hopefully this helps, tested here in dotnetfiddle
Edit:
this might get you started into building the right expression according to whatever patterns you are falling into and maybe build a recursive function to parse the rest into the desired output :)
RegEx is not recursive. You either count bracket level, or recurse.
An non-recursive parser loop I tested for the example you show is..
string SplitFirstLevel(string s)
{
List<string> result = new List<string>();
int p = 0, level = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '(')
{
level++;
if (level == 1) p = i + 1;
if (level == 2)
{
result.Add('"' + s.Substring(p, i - p) + '"');
p = i;
}
}
if (s[i] == ')')
if (--level == 0)
result.Add('"' + s.Substring(p, i - p) + '"');
}
return "[" + String.Join(",", result) + "]";
}
Note: after some more testing, I see your specification is unclear. How to delimit orphaned level 1 terms, that is terms without bracketing ?
For example, my parser translates
(example (to (parsing nested paren) but) (first lvl only))
to:
["example ","(to (parsing nested paren) but) ","(first lvl only)"]
and
(example (to (parsing nested paren)) but (first lvl only))
to:
["example ","(to (parsing nested paren)) but ","(first lvl only)"]
In either case, "example" gets a separate term, while "but" is grouped with the first term. In the first example this is logical, it is in the bracketing, but it may be unwanted behaviour in the second case, where "but" should be separated, like "example", which also has no bracketing (?)

Use foreach to loop through list (or array) as sequence of pairs

I'm creating a simple program that reads username and password from Customers.txt file and verifies if it's correct. Customer.txt is formatted to have sequence of the username then password separated by commas (ignore safety concerns for the exercise):
JohnDoe,1234,JaneDoe,5678,...
Is it possible to create a foreach loop to iterate through the strArray[] and check pairs {strArray[0], strArray[1]} then {strArray[2],strArray[3]} and so on to see if user put the right credentials?
private void enter_click_Click(object sender, RoutedEventArgs e)
{
StreamReader reader1 = new StreamReader("Customers.txt");
string text = reader1.ReadToEnd();
reader1.Close();
string[] Strarray = text.Split(',');
StreamReader reader2 = new StreamReader("Admin.txt");
string text2 = reader2.ReadToEnd();
reader2.Close();
string[] AdminArray = text2.Split(',');
if (username_txt.Text == AdminArray[0] && passwordBox1.Password == AdminArray[1])
{
AdminPage admin = new AdminPage();
admin.Activate();
admin.Show();
method.CheckDate();
return;
}
if (username_txt.Text == Strarray[0] && passwordBox1.Password == Strarray[1])
{
ATM_Screen atm = new ATM_Screen();
atm.Activate();
atm.Show();
method.CheckDate();
return;
}
Yes, you can do this:
var usernames = Strarray.Where((s, i) => { return i % 2 == 0; });
var passwords = Strarray.Where((s, i) => { return i % 2 != 0; });
var userPasswords = usernames.Zip(passwords, (l, r) => new { username = l, password = r });
foreach(var userPassword in userPasswords) {
if (userPassword.username == "rob" && userPassword.password == "robspassword") {
}
}
Edit based on comment:
You can do this for multiple valid credentials:
var allowedCredentials = new List<Tuple<String, String>> {
new Tuple<String, String>("Rob", "Robspassword"),
new Tuple<String, String> ("SomeoneElse", "SomeoneElsespassword"
};
var inputCredentials = new List<string> { "Rob","Robspassword","Rob","Notrobspassword" };
var usernames = inputCredentials.Where((s, i) => { return i % 2 == 0; });
var passwords = inputCredentials.Where((s, i) => { return i % 2 != 0; });
var userPasswords = usernames.Zip(passwords, (l, r) => new { username = l, password = r });
foreach(var userPassword in userPasswords) {
if (allowedCredentials.Any(ac => ac.Item1 == userPassword.username
&& ac.Item2 == userPassword.password)
{
//Valid
}
}
Using foreach is kind of hard to get pairs of elements from sequence:
you can iterate through sequence normally and remember first element on the odd iterations, perform operation on every even iteration
you can convert sequence into pairs first using LINQ and indexing or Zip even and odd half.
Collecting pairs approach:
string name;
bool even = false;
foreach(var text in items)
{
if (even)
{
var password = item;
// check name, password here
}
else
{
name = text;
}
even = !even;
}
Zip-based approach
foreach(var pair in items
.Where((v,id)=>id % 2 == 1) // odd - names
.Zip(items.Where((v,id)=>id % 2 == 0), // even - passwords
(name,password)=> new { Name = name, Password = password}))
{
// check pair.Name, pair.Password
}
Note: It would be much easier to use regular for loop with increment of 2.

How to write a function that generates ID by taking missing items in a sequence?

How can I write an algorithm that can take unused ID's out of a sequence starting from 1 to 99 in the format "C00"? For example NewId(['C01', 'C02', 'C03']) should emit 'C04', but NewId(['C02', 'C03', 'C04']) should emit C01, and NewId(['C01', 'C03', 'C04']) should result in C02.
I wrote an implementation but the result is wrong.
Example : CAT_ID : C01, C02, C05, C06, C11. When I run it, the expected result is C03. My algorithm is as follows:
Sort ID asc
Go through every item in the list
Compare first value with the next, if they are not the same, add 1 and exit loop.
This is my code:
public static string Get_AreaID_Auto()
{
string result = "";
if (db.TESTs.ToList().Count <= 0)
{
result = "01";
}
else
{
int maxId = 0;
foreach (var item in db.TESTs.OrderBy(e => e.CAT_ID).ToList())
{
if (int.Parse(item.CAT_ID.Substring(1)) + 1 != int.Parse(item.CAT_ID.Substring(1)))
{
maxId = int.Parse(item.CAT_ID.Substring(1) + 1);
break;
}
}
switch (maxId.ToString().Length)
{
case 1:
if (maxId == 9)
{
result = "10";
}
else
result = "0" + (maxId + 1);
break;
case 2:
result = "" + (maxId + 1);
break;
default:
break;
}
}
return "C" + result;
}
Can someone point out what is wrong?
This should work for you:
public static string Get_AreaID_Auto()
{
var existing = db.TESTs.Select(e => e.CAT_ID).OrderBy(x => x).ToList();
if (existing.Count == 0)
{
return "C01";
}
else
{
return
existing
.Concat(new [] { "" })
.Select((x, n) => new
{
actual = x,
expected = String.Format("C{0:00}", n + 1),
})
.Where(x => x.actual != x.expected)
.Select(x => x.expected)
.First();
}
}
This uses a generate and test approach. No parsing necessary.
I just realised with the .Concat(new [] { "" }) change that the if statement is now no longer required. You can do this instead:
public static string Get_AreaID_Auto()
{
return
db.TESTs
.Select(e => e.CAT_ID)
.OrderBy(x => x)
.ToArray()
.Concat(new [] { "" })
.Select((x, n) => new
{
actual = x,
expected = String.Format("C{0:00}", n + 1),
})
.Where(x => x.actual != x.expected)
.Select(x => x.expected)
.First();
}
Try this
public static string Get_AreaID_Auto()
{
string result = "";
if (db.TESTs.ToList().Count <= 0)
{
result = "01";
}
else
{
var item = db.TESTs.OrderByDescending(e => e.CAT_ID).First();
result = int.Parse(item.CAT_ID.Substring(1)) + 1;
}
return string.Format("C{0:D3}",result);
}
Updated Code...Now Try this
public static string Get_AreaID_Auto()
{
string result = "";
if (db.TESTs.ToList().Count <= 0)
{
result = "01";
}
else
{
var items = db.TESTs.OrderBy(e => e.CAT_ID).ToArray();
for(int i=0;i<items.count;i++)
{
if ((i==items.count-1) || (int.Parse(items[i].CAT_ID.Substring(1)) + 1 != int.Parse(items[i+1].CAT_ID.Substring(1))))
{
result = int.Parse(items[i].CAT_ID.Substring(1) + 1);
break;
}
}
}
return string.Format("C{0:D2}",result);
}
Here is a solution I think would work:
var items = db.TESTs.Select(x => int.Parse(x.CAT_ID.Substring(1))).OrderBy(v => v).ToArray();
if(!items.Any())
return "C01";
int current = 0;
for (int i = 0; i < items.Length; i++)
{
if (items[i] > current + 1)
return "C" + (current + 1) .ToString("00");
current = items[i];
}
return "C" + (items.Max() + 1).ToString("00");

C# (String.StartsWith && !String.EndsWith && !String.Contains) using a List

I am a newbie in C#, and I am having problems.
I have 2 List, 2 strings and a getCombinations(string) method that
returns all combinations of a string as List;
How do i validate if a subjectStrings element does not
StartWith && !EndsWith && !Contains (or !StartWith && !EndsWith && Contains, etc.)
for every combinations of startswithString, endswithString and containsString?
Here is my code in StartWith && !EndsWith
(if you want to see it running: http://ideone.com/y8JZkK)
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
List<string> validatedStrings = new List<string>();
List<string> subjectStrings = new List<string>()
{
"con", "cot", "eon", "net", "not", "one", "ten", "toe", "ton",
"cent", "cone", "conn", "cote", "neon", "none", "note", "once", "tone",
"cento", "conte", "nonce", "nonet", "oncet", "tenon", "tonne",
"nocent","concent", "connect"
}; //got a more longer wordlist
string startswithString = "co";
string endswithString = "et";
foreach(var z in subjectStrings)
{
bool valid = false;
foreach(var a in getCombinations(startswithString))
{
foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
if(valid)
{
break;
}
}
if(valid)
{
validatedStrings.Add(z);
}
}
foreach(var a in validatedStrings)
{
Console.WriteLine(a);
}
Console.WriteLine("\nDone");
}
static List<string> getCombinations(string s)
{
//Code that calculates combinations
return Permutations.Permutate(s);
}
}
public class Permutations
{
private static List<List<string>> allCombinations;
private static void CalculateCombinations(string word, List<string> temp)
{
if (temp.Count == word.Length)
{
List<string> clone = temp.ToList();
if (clone.Distinct().Count() == clone.Count)
{
allCombinations.Add(clone);
}
return;
}
for (int i = 0; i < word.Length; i++)
{
temp.Add(word[i].ToString());
CalculateCombinations(word, temp);
temp.RemoveAt(temp.Count - 1);
}
}
public static List<string> Permutate(string str)
{
allCombinations = new List<List<string>>();
CalculateCombinations(str, new List<string>());
List<string> combinations = new List<string>();
foreach(var a in allCombinations)
{
string c = "";
foreach(var b in a)
{
c+=b;
}
combinations.Add(c);
}
return combinations;
}
}
Output:
con
cot
cone
conn
cote <<<
conte <<<
concent
connect
Done
if(z.StartsWith(a) && !z.EndsWith(b))
var b can be "et" and "te", but cote and conte endswith "te",
why it is still added in my validated strings?
Thanks in advance.
z.StartsWith(a) && !z.EndsWith(b)
check below combination
z ="cote"
a ="co"
b ="te"
so z start with "co" and z not end with "te", your condition pass and cote will add to list
i would try as below
var sw =getCombinations(startswithString);
var ew = getCombinations(endswithString);
var result = subjectStrings.Where(z=>
sw.Any(x=>z.StartsWith(x) &&
!ew.Any(y=>z.EndsWith(y))))
.ToList();
DEMO
output :
con
cot
cone
conn
concent
connect
foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
here you are setting valid to true as soon as there is match for !z.EndsWith(b) and you are not traversing the whole list of permutations available.
since "cote" doesn't end with "et" it is a match and valid is set to true and the code breaks.
So that's why "cote" is added to your list of valid strings. So is the case with "conte".
What you want to do is :
List<string> startsWithCombination = getCombinations("co");
List<string> endsWithCombination = getCombinations("et");
foreach (var z in subjectStrings)
{
bool isStartMatchFound = startsWithCombination.Any(b => z.StartsWith(b));
if (isStartMatchFound)
{
bool isEndMatchFound = endsWithCombination.Any(b => z.EndsWith(b));
if (!isEndMatchFound)
{
validatedStrings.Add(z);
}
}
}

Categories