I am working on c# application and i want to accomplish following task:
I have 12 check boxes for 12 items and user can check any of the check boxes.
if check boxes 3,4,5,6,8,10,11,12 have been checked, I would like to display following output.
You have selected items 3-6,8,10-12.
Rules:
When consecutive number group count is 3 or more than 3,Show grouping like 3-6
else show individual number. 8
Firstly I suggest you to append value of all the checkbox in string like you have shown.
Function Calling :
string data = "3,5,6,7,8,10,12";
string res = GetResultString(data);
Functions :
string GetResultString(string data)
{
string[] arrData = data.Split(',').ToArray();
List<int> lstData = new List<int>();
foreach (string item in arrData)
{
lstData.Add(Convert.ToInt16(item));
}
lstData.Sort();
string finalStr = string.Empty;
if (lstData.Count > 0)
{
int start = lstData[0];
int end = start;
finalStr = string.Empty;
for (int index = 1; index < lstData.Count; index++)
{
if (end + 1 == lstData[index])
{
end = lstData[index];
}
else
{
finalStr += appendResult(start, end);
start = -1;
}
if (start == -1)
{
start = lstData[index];
end = lstData[index];
}
}
finalStr += appendResult(start, end);
}
finalStr = finalStr.Trim(',');
return finalStr;
}
string appendResult(int start,int end)
{
string res = string.Empty;
if (end - start > 1)
{
res += start + "-" + end.ToString() + ",";
start = -1;
}
else
{
while (start <= end)
{
res += start.ToString() + ",";
start++;
}
}
return res;
}
Hope this will done your job,
try this .. it will work i tested it
I have not created checkboxes so it is up to you to check which checkbox is selected get the string like from the selected checkboxes 3,4,5,6,8,10,11,12
string str1 = "3,4,5,6,8,10,11,12";
string[] strArr = str1.Split(',');
List<string> strFinal = new List<string>();
int[] myInts = Array.ConvertAll(strArr, s => int.Parse(s));
int arrLn = myInts.Length;
Array.Sort(myInts);
int intPrevVal = myInts[0];
int intPrevDiff = myInts[0];
int seriesCount = 1;
strFinal.Add(Convert.ToString(myInts[0]));
for (int j = 1; j < arrLn; j++)
{
int intCurr = myInts[j];
if (intCurr - intPrevVal == 1)
{
seriesCount++;
}
else
{
if (seriesCount >= 3)
{
strFinal[strFinal.Count - 1] = strFinal[strFinal.Count - 1] + "-" + intPrevVal;
seriesCount = 1;
}
else if (seriesCount == 2)
{
strFinal.Add(Convert.ToString(myInts[j - 1]));
seriesCount = 1;
//strFinal.Add(Convert.ToString(myInts[j]));
}
strFinal.Add(Convert.ToString(myInts[j]));
}
intPrevVal = intCurr;
}
if (seriesCount >= 3)
{
strFinal[strFinal.Count - 1] = strFinal[strFinal.Count - 1] + "-" + myInts[arrLn - 1];
}
else if (seriesCount == 2)
{
strFinal.Add(Convert.ToString(myInts[arrLn - 1]));
}
string FinalAns = string.Join(",", strFinal.ToArray());
Response.Write(FinalAns);
I suppose you did your checkbox with array (new...) if not do it maunally...
int min=13;
int max=0;
string s = "";
for (int i = 0; i<12; i++)
{
if (cb[i].checked && i<min)
min = i;
else if (cb[i].checked == false)
if (min != 13)
{
max = i-1;
s = s + min.ToString() + "-" + max.ToString() + " ";
min = 13;
}
}
if (cb[11].checked) s = s + min.ToString() + "-12"; // for case the last one is checked
// s contains your data
(I didn't check it but I think it need to be something like this.)
try this
var data = new List<int> { 3, 4, 5, 6, 8, 10, 11, 12 };
// data.Sort();
var groups = new List<string>();
var startIndex = 0;
for (var i = 1; i < data.Count; i++)
{
if (data[i - 1] == data[i] - 1)
{
continue;
}
groups.Add(startIndex == i - 1
? data[startIndex].ToString()
: data[startIndex] + "-" + data[i - 1] );
startIndex = i;
}
groups.Add(startIndex == data.Count - 1
? data[startIndex].ToString()
: data[startIndex] + "-" + data[data.Count - 1]);
var result = string.Join(",", groups);
version 2
[Fact]
public void Test()
{
var data = new List<int> { 3, 4, 5, 7, 8, 10, 11, 12 };
// data.Sort();
var groups = new List<string>();
var startIndex = 0;
for (var i = 1; i < data.Count; i++)
{
if (data[i - 1] == data[i] - 1)
{
continue;
}
AddToGroups(groups, startIndex, i, data);
startIndex = i;
}
AddToGroups(groups, startIndex, data.Count, data);
var result = string.Join(",", groups);
Assert.Equal("3-5,7,8,10-12", result);
}
private static void AddToGroups(List<string> groups, int startIndex, int actualIndex, List<int> data)
{
switch (actualIndex - startIndex)
{
case 1:
groups.Add(data[startIndex].ToString());
break;
case 2:
groups.Add(data[startIndex].ToString());
groups.Add(data[startIndex + 1].ToString());
break;
default:
groups.Add(data[startIndex] + "-" + data[actualIndex - 1]);
break;
}
}
You might have got the solution,but all the above solutions use string for appending data..You could use StringBuilder for optimized performance.
List<int> selectedCB = new List<int>() { 3, 4, 6, 7, 8, 9, 11, 12 };
string output = GetFormattedOutput(selectedCB);
The code for formatting data..
private string GetFormattedOutput(List<int> selectedCB)
{
// Can be changed if you want to increase
// groupby range
int rangeBy = 3;
int diffBy = 1;
int prevValue = 0;
List<int> tempList = new List<int>();
StringBuilder formattedOutput = new StringBuilder();
foreach (int currentValue in selectedCB)
{
var diff = currentValue - prevValue;
if(tempList.Count != 0 && diff > diffBy)
{
// Add the value in templist to formatted output
// If three are more numbers are in range
// Add the first and last
if (tempList.Count >= rangeBy)
{
formattedOutput.Append(tempList[0].ToString() + "-" +
tempList[tempList.Count - 1].ToString()+",");
}
else
{
AppendText(formattedOutput, tempList);
}
tempList.Clear();
}
tempList.Add(currentValue);
prevValue = currentValue;
}
if (tempList.Count != 0)
{
AppendText(formattedOutput, tempList);
}
formattedOutput.Remove(formattedOutput.Length - 1, 1);
return formattedOutput.ToString();
}
// To append the numbers in the list
string AppendText(StringBuilder output, List<int> tempList)
{
foreach (var temp in tempList)
{
output.Append(temp.ToString() + ",");
}
return output.ToString();
}
Related
I have a problem with string in C#. I get this string from database, and it contains quote signs ("), so my program doesn't read it correctly.
string attributes = databaseFunctions.GetVariationAttributes(produc_id);
My string in the database is
a:3:{s:9:"variation";a:6:{s:4:"name";s:9:"Variation";s:5:"value";s:24:"type a | type b | type c";s:8:"position";s:1:"0";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"1";s:11:"is_taxonomy";s:1:"0";}s:5:"color";a:6:{s:4:"name";s:5:"Color";s:5:"value";s:27:"RED | BLUE | WHITE | ORANGE";s:8:"position";s:1:"1";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"1";s:11:"is_taxonomy";s:1:"0";}s:4:"test";a:6:{s:4:"name";s:4:"TEST";s:5:"value";s:15:"120 | 140 | 160";s:8:"position";s:1:"2";s:10:"is_visible";s:1:"1";s:12:"is_variation";s:1:"0";s:11:"is_taxonomy";s:1:"0";}}
This is actually the Woocommerce product variation attributes. I need to get each attribute, check if it is used for variations, and if yes, get its name and possible values.
Maybe you have any idea how to do it? I'm trying to use substrings and IndexOf functions (Get index of the first and second colon, then get value from between them and use it in a loop)
I will appreciate any of your advice
[EDIT]
Ok, I did it. It's not the prettiest solution, but it works. I post it here, so others may use it in a similar situation
if(databaseFunctions.CheckVariations(variations))
{
string attributes = databaseFunctions.GetVariationAttributes(produc_id);
List<List<string>> parameters = new List<List<string>>();
List<List<string>> values = new List<List<string>>();
int i_1 = 0;
int i_2 = 0;
//First ':'
int c_1 = attributes.IndexOf(':');
//Second ':'
int c_2 = attributes.IndexOf(':', c_1 + 1);
//First 'a' - number of attributes
int a_1 = Convert.ToInt32(attributes.Substring(c_1 + 1, c_2-c_1 -1));
//For each attribute
for (int i = 0; i < a_1; i++)
{
List<string> parameters_of_attribute = new List<string>();
List<string> values_of_attribute = new List<string>();
//First ':'
int ac_1 = attributes.IndexOf(':', c_2 + 1 + i_1);
//Second ':'
int ac_2 = attributes.IndexOf(':', ac_1 + 1);
//First ':' of a
int kc_1 = attributes.IndexOf(':', ac_2 + 1);
//Second ':' of a
int kc_2 = attributes.IndexOf(':', kc_1 + 1);
//Number of parameter-value pairs
int p_v = Convert.ToInt32(attributes.Substring(kc_1 + 1, kc_2 - kc_1 - 1));
//For each parameter-value pair
for (int j = 0; j < p_v; j++)
{
//First '"' of parameter
int pq_1 = attributes.IndexOf('"', kc_2 + 1 + i_2);
//Second '"' of parameter
int pq_2 = attributes.IndexOf('"', pq_1 + 1);
//Name of parameter
string par = attributes.Substring(pq_1 + 1, pq_2 - pq_1 - 1);
//First '"' of value
int vq_1 = attributes.IndexOf('"', pq_2 + 1);
//Second '"' of value
int vq_2 = attributes.IndexOf('"', vq_1 + 1);
//Value of parameter
string val = attributes.Substring(vq_1 + 1, vq_2 - vq_1 - 1);
parameters_of_attribute.Add(par);
values_of_attribute.Add(val);
i_2 = vq_2 - kc_2;
}
parameters.Add(parameters_of_attribute);
values.Add(values_of_attribute);
i_1 = i_2 + kc_2 - c_2;
i_2 = 0;
}
}
Gordon Breuer published code to read PHP's serialized data format using C# at https://gordon-breuer.de/unknown/2011/05/04/php-un-serialize-with-c.html - unfortunately this is not available as a NuGet package (yet!) - it's based off dinosaur code written for .NET Framework 1.0 back in 2001.
I'm repeating the code below for preservation's sake with extra copyright/origin info (Blogs aren't around forever). According to the original SourceForge project's page the code is licensed under the OSI-approved IBM CPL.
/*
* Serializer.cs
* This is the Serializer class for the PHPSerializationLibrary
*
* https://sourceforge.net/projects/csphpserial/
*
* Copyright 2004 Conversive, Inc. Licensed under Common Public License 1.0
*
* Modified for WP7-Silverlight by Gordon Breuer
* https://gordon-breuer.de/unknown/2011/05/04/php-un-serialize-with-c.html
*
* Updated to be thread-safe and correctly reentrant and with C# 7.0 features added for https://stackoverflow.com/questions/58384540/c-sharp-string-with-from-database-cannot-do-interpolation/
*
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Conversive.PHPSerializationLibrary {
public class PhpSerializer
{
//types:
// N = null
// s = string
// i = int
// d = double
// a = array (hashtable)
private static readonly NumberFormatInfo _nfi = new NumberFormatInfo { NumberGroupSeparator = "", NumberDecimalSeparator = "." };
public Encoding StringEncoding { get; }
/// <summary>Whether or not to strip carriage returns from strings when serializing and adding them back in when deserializing</summary>
public Boolean XmlSafe { get; }
public PhpSerializer()
: this( encoding: new UTF8Encoding(), xmlSafe: true )
{
}
public PhpSerializer( Encoding encoding, Boolean xmlSafe )
{
this.StringEncoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
this.XmlSafe = xmlSafe;
}
private class SerializeState
{
public readonly StringBuilder sb = new StringBuilder();
// These collections used for cycle-detection.
public readonly HashSet<Object> seenCollections = new HashSet<Object>();
}
public String Serialize(object obj)
{
SerializeState state = new SerializeState();
this.Serialize(obj, state );
return state.sb.ToString();
}
//Serialize(object obj)
private void Serialize( Object obj, SerializeState state )
{
StringBuilder sb = state.sb;
if (obj == null)
{
sb.Append("N;");
}
else if (obj is string str)
{
if (XmlSafe)
{
str = str.Replace("rn", "n"); //replace rn with n
str = str.Replace("r", "n"); //replace r not followed by n with a single n Should we do this?
}
sb.Append("s:" + StringEncoding.GetByteCount(str) + ":" + str + ";");
}
else if (obj is bool b)
{
sb.Append("b:" + ( b ? "1" : "0") + ";");
}
else if (obj is int objInt)
{
sb.Append("i:" + objInt.ToString(_nfi) + ";");
}
else if (obj is double objDbl)
{
sb.Append("d:" + objDbl.ToString(_nfi) + ";");
}
else if ( (obj is IReadOnlyDictionary<object, object> ) || ( obj is IDictionary<object, object> ) )
{
if (state.seenCollections.Contains(obj))
{
sb.Append("N;");
}
else
{
state.seenCollections.Add(obj);
IEnumerable<KeyValuePair<Object,Object>> asDictEnum = (IEnumerable<KeyValuePair<Object,Object>>)obj;
sb.Append("a:" + asDictEnum.Count() + ":{");
foreach (var entry in asDictEnum)
{
this.Serialize(entry.Key, state);
this.Serialize(entry.Value, state);
}
sb.Append("}");
}
}
else if (obj is IEnumerable<object> enumerable)
{
if (state.seenCollections.Contains( enumerable ) )
{
sb.Append("N;");
}
else
{
state.seenCollections.Add(enumerable);
IReadOnlyList<Object> asList = enumerable as IReadOnlyList<Object>; // T[] / Array<T> implements IReadOnlyList<T> already.
if( asList == null ) asList = enumerable.ToList();
sb.Append("a:" + asList.Count + ":{");
Int32 i = 0;
foreach( Object item in asList )
{
this.Serialize(i, state);
this.Serialize( item, state);
i++;
}
sb.Append("}");
}
}
else
{
throw new SerializationException( "Value could not be serialized." );
}
}
public Object Deserialize(String str)
{
Int32 pos = 0;
return this.Deserialize(str, ref pos );
}
private Object Deserialize( String str, ref Int32 pos )
{
if( String.IsNullOrWhiteSpace( str ) )
return new Object();
int start, end, length;
string stLen;
switch( str[pos] )
{
case 'N':
pos += 2;
return null;
case 'b':
char chBool = str[pos + 2];
pos += 4;
return chBool == '1';
case 'i':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
var stInt = str.Substring(start, end - start);
pos += 3 + stInt.Length;
return Int32.Parse(stInt, _nfi);
case 'd':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
var stDouble = str.Substring(start, end - start);
pos += 3 + stDouble.Length;
return Double.Parse(stDouble, _nfi);
case 's':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
var bytelen = Int32.Parse(stLen);
length = bytelen;
if ((end + 2 + length) >= str.Length) length = str.Length - 2 - end;
var stRet = str.Substring(end + 2, length);
while (StringEncoding.GetByteCount(stRet) > bytelen)
{
length--;
stRet = str.Substring(end + 2, length);
}
pos += 6 + stLen.Length + length;
if (XmlSafe) stRet = stRet.Replace("n", "rn");
return stRet;
case 'a':
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
length = Int32.Parse(stLen);
var htRet = new Dictionary<object, object>(length);
var alRet = new List<object>(length);
pos += 4 + stLen.Length; //a:Len:{
for (int i = 0; i < length; i++)
{
var key = this.Deserialize(str, ref pos);
var val = this.Deserialize(str, ref pos);
if (alRet != null)
{
if (key is int && (int)key == alRet.Count)
alRet.Add(val);
else
alRet = null;
}
htRet[key] = val;
}
pos++;
if( pos < str.Length && str[pos] == ';')
{
pos++;
}
return alRet != null ? (object)alRet : htRet;
default:
return "";
}
}
}
}
When I run this in Linqpad with your input I get this result output:
void Main()
{
const String attribs = #"a:3:{s:9:""variation"";a:6:{s:4:""name"";s:9:""Variation"";s:5:""value"";s:24:""type a | type b | type c"";s:8:""position"";s:1:""0"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""1"";s:11:""is_taxonomy"";s:1:""0"";}s:5:""color"";a:6:{s:4:""name"";s:5:""Color"";s:5:""value"";s:27:""RED | BLUE | WHITE | ORANGE"";s:8:""position"";s:1:""1"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""1"";s:11:""is_taxonomy"";s:1:""0"";}s:4:""test"";a:6:{s:4:""name"";s:4:""TEST"";s:5:""value"";s:15:""120 | 140 | 160"";s:8:""position"";s:1:""2"";s:10:""is_visible"";s:1:""1"";s:12:""is_variation"";s:1:""0"";s:11:""is_taxonomy"";s:1:""0"";}}";
PhpSerializer s = new PhpSerializer();
Object result = s.Deserialize( attribs );
result.Dump();
}
Visualized output:
This is the sample textfile
Line is categorized by date, per line date can be repeated like for example, December 1 and 2 have two entries. Expected Output should be counting the pattern "D;" for example per date
2016-12-01 - 7
2016-12-02 - 9
2016-12-03 - 5
This is what I currently have
using (StreamReader stRead = new StreamReader(FileUpload1.PostedFile.InputStream))
{
while (!stRead.EndOfStream)
{
var readedLine = stRead.ReadLine();
if (!string.IsNullOrWhiteSpace(readedLine))
{
for (int j = 01; j <= 31; j++)
{
int readedLineTime = Convert.ToInt32(readedLine.Substring(09, 02));
if (readedLineTime == j)
{
MatchCollection collection = Regex.Matches(readedLine, #"D;");
countedChars = collection.Count;
textfileOutput += readedLine.Substring(0, 11) + " - " + countedChars + Environment.NewLine;
}
}
}
textfileContent += readedLine + Environment.NewLine;
i++;
}
TextBox1.Text = textfileOutput;
TextBox2.Text = textfileContent;
Label1.Text = i.ToString();
//Label1.Text = this.TextBox1.Text.Split(new Char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Length.ToString();
// Label2.Text = filename;
}
and this is its current output that is being displayed in multiple line textbox
2016-12-01 - 4
2016-12-01 - 3
2016-12-02 - 4
2016-12-02 - 5
2016-12-03 - 5
Let me know if this works.
Dictionary<string, int> dMyobject = new Dictionary<string, int>();
while (!stRead.EndOfStream)
{
var readedLine = stRead.ReadLine();
if (!string.IsNullOrWhiteSpace(readedLine))
{
int readedLineTime = Convert.ToInt32(readedLine.Substring(09, 02));
string sDate = readedLine.Substring(0, 11);
MatchCollection collection = Regex.Matches(readedLine, #"D;");
countedChars = collection.Count;
if (!dMyobject.Keys.Contains(sDate))
{
dMyobject.Add(sDate, collection.Count);
}
else
{
dMyobject[sDate] = dMyobject[sDate] + collection.Count;
}
}
textfileContent += readedLine + Environment.NewLine;
i++;
}
You will need to push these values in some collection. So that you can check it.
Later, for using these values for printing or anything, use following
foreach (var item in dMyobject)
{
Console.WriteLine(item.Key + " " + item.Value);
}
string line = "";
Dictionary<string, int> list = new Dictionary<string, int>();
int count;
if (File.Exists(fileName) == true)
{
StreamReader objReader;
objReader = new StreamReader(fileName);
StreamWriter file = new StreamWriter(OutputfileName");
do
{
line = objReader.ReadLine();
string temp = line.Substring(0, 10);
if (!list.ContainsKey(temp))
{
MatchCollection collection = Regex.Matches(line, #"D;");
count = collection.Count;
list.Add(temp, count);
}
else
{
MatchCollection collection = Regex.Matches(line, #"D;");
count = collection.Count;
var val = list[temp];
list[temp] = count + val;
}
} while (objReader.Peek() != -1);
foreach (var j in list)
{
file.WriteLine(j.Key + " - " + j.Value+"\n");
}
file.Close();
}
I have a []string retry and I have some strings inside of it let's say:
a 2 , a 3 , h 9, asd 123 and so on. They all have intervals between the letter and the integer. Now I need to get how long is the letter part (in this case "qwe 2" the letter length is 3 and the integer part is 2). I'm later using .substring from the specified index at which the letter part finishes and the integer one starts.
string[] s = new string[5];
List<string> retry = new List<string>();
int max = 1;
for (int i = 0; i < s.Length; i++)
{
s[i] = Console.ReadLine();
}
Console.WriteLine(" ");
Array.Sort(s);
for (int j = 0; j < s.Length; j++)
{
if (j > 0)
{
if (s[j] == s[j - 1])
{
max++;
if (retry.Any(x => x.Contains(s[j])))
{
retry.Add(s[j] + " " + max);
}
else
{
if (j <= s.Length - 1)
{
if (s[j-1] != s[j])
{
retry.Add(s[j] + " " + max);
}
else
{
retry.Add(s[j] + " " + max);
}
}
}
}
else
{
max = 1;
}
}
}
for (int j = 0; j < retry.ToArray().Length; j++)
{
for (int k = j + 1; k < retry.ToArray().Length; k++)
{
var a1=retry[j].Substring(0,1);
var a2 = retry[k].Substring(0,1);
if(a1==a2)
{
var b1 = retry[j].Substring(2);
var b2 = retry[k].Substring(2);
if(int.Parse(b1)>int.Parse(b2))
{
retry.Remove(a2 + " "+ b2);
}
else
{
retry.Remove(a1 + " " + b1);
}
}
}
Console.WriteLine(retry[j]);
}
Console.ReadKey();
This only works for 1 letter.
The code below should get the result as expected:
string [] entries = {"xyz 1","q 2","poiuy 4"};
for(int i=0;i<entries.Length;i++)
{
var parts = entries[i].Split(' ');
var txtCount = parts[0].Length;
Console.WriteLine(String.Format("{0} {1}", txtCount, parts[1]));
}
How about...
string[] test = new [] { "qwe 2", "a 2", "b 3", "asd 123" };
foreach (var s in test)
{
var lastLetterIndex = Array.FindLastIndex(s.ToCharArray(), Char.IsLetter);
var lastNumberIndex = Array.FindLastIndex(s.ToCharArray(), Char.IsNumber);
Console.WriteLine(s);
Console.WriteLine("Letter Length : " + (lastLetterIndex + 1));
Console.WriteLine("Number Length : " + (lastNumberIndex - lastLetterIndex));
}
Console.ReadKey();
This iterates through all of the strings and counts the length of the chars, and stores the value of the number, as well as its index. Note that this information is lost upon each iteration, but I'll leave it to you to worry about storing that if you need that information for longer than the duration of an iteration.
int letterLength = 0, number = 0, index = 0;
string[] testString = { "a 2", "a 3", "h 9", "asd 123", "sw", "swa23", "swag 2464" };
foreach (string str in testString)
{
letterLength = 0;
index = -1;
int i = 0;
for (; i < str.Length; i++)
{
char c = str[i];
if (Char.IsLetter(c)) letterLength++;
else if (Char.IsNumber(c)) break;
}
StringBuilder strBuilder = new StringBuilder();
for (; i < str.Length; i++)
{
char c = str[i];
if (index == -1) index = str.IndexOf(c);
strBuilder.Append(c);
number = Int32.Parse(strBuilder.ToString());
}
Console.WriteLine($"String: {str}\nLetter Length: {letterLength} Number: {number} Index: {index}\n");
}
So let me start by saying that I'm a newbie with little to moderate knowledge about C#.
Coming to the topic: I need to make a program that is able to add/subtract very large integers. Initially, used BigInt only to find out it's not allowed. There should be a logical workaround for this? I have an idea which is using "elementary school method" where you add each digit starting from right to left.
I made a string which I split into char array and added each digit from right to left(GetUpperBound-i). But it doesn't seem to work.
My Code:
string s, s2;
char[] c_arr, c_arr2;
int i, erg;
s = "1234";
s2 = "5678";
c_arr = s.ToCharArray();
c_arr2 = s2.ToCharArray();
for (i = 0; i <= c_arr.GetUpperBound(0); i++)
{
erg = c_arr[c_arr.GetUpperBound(0)-i]+c_arr2[c_arr2.GetUpperBound(0)-i];
Console.Write(erg);
}
Console.ReadKey();
There are a few things wrong with your code for the 'elementary school method'. You don't account for carry, you're adding up ascii values rather than actual values between 0-9, and you're outputting the results in the wrong order.
The code below, whilst not very elegant, does produce the correct results:
var s1 = "12345";
var s2 = "5678";
var carry = false;
var result = String.Empty;
if(s1.Length != s2.Length)
{
var diff = Math.Abs(s1.Length - s2.Length);
if(s1.Length < s2.Length)
{
s1 = String.Join("", Enumerable.Repeat("0", diff)) + s1;
}
else
{
s2 = String.Join("", Enumerable.Repeat("0", diff)) + s2;
}
}
for(int i = s1.Length-1;i >= 0; i--)
{
var augend = Convert.ToInt32(s1.Substring(i,1));
var addend = Convert.ToInt32(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
Console.WriteLine(result);
The following program can be used to add two large numbers, I have used string builder to store the result. You can add numbers containing digits upto '2,147,483,647'.
Using System;
using System.Text;
using System.Linq;
public class Test
{
public static void Main()
{
string term1="15245142151235123512352362362352351236";
string term2="1522135123612646436143613461344";
StringBuilder sum=new StringBuilder();
int n1=term1.Length;
int n2=term2.Length;
int carry=0;
int n=(n1>n2)?n1:n2;
if(n1>n2)
term2=term2.PadLeft(n1,'0');
else
term1=term1.PadLeft(n2,'0');
for(int i=n-1;i>=0;i--)
{
int value=(carry+term1[i]-48+term2[i]-48)%10;
sum.Append(value);
carry=(carry+term1[i]-48+term2[i]-48)/10;
}
char[] c=sum.ToString().ToCharArray();
Array.Reverse(c);
Console.WriteLine(c);
}
}
string Add(string s1, string s2)
{
bool carry = false;
string result = string.Empty;
if(s1[0] != '-' && s2[0] != '-')
{
if (s1.Length < s2.Length)
s1 = s1.PadLeft(s2.Length, '0');
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for(int i = s1.Length-1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
}
else if(s1[0] == '-' || s2[0] == '-')
{
long sum = 0;
if(s2[0] == '-')
{
//Removing negative sign
char[] MyChar = {'-'};
string NewString = s2.TrimStart(MyChar);
s2 = NewString;
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for (int i = s1.Length - 1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
if(augend >= addend)
{
sum = augend - addend;
}
else
{
int temp = i - 1;
long numberNext = Convert.ToInt64(s1.Substring(temp,1));
//if number before is 0
while(numberNext == 0)
{
temp--;
numberNext = Convert.ToInt64(s1.Substring(temp,1));
}
//taking one from the neighbor number
int a = int.Parse(s1[temp].ToString());
a--;
StringBuilder tempString = new StringBuilder(s1);
string aString = a.ToString();
tempString[temp] = Convert.ToChar(aString);
s1 = tempString.ToString();
while(temp < i)
{
temp++;
StringBuilder copyS1 = new StringBuilder(s1);
string nine = "9";
tempString[temp] = Convert.ToChar(nine);
s1 = tempString.ToString();
}
augend += 10;
sum = augend - addend;
}
result = sum.ToString() + result;
}
//Removing the zero infront of the answer
char[] zeroChar = {'0'};
string tempResult = result.TrimStart(zeroChar);
result = tempResult;
}
}
return result;
}
string Multiply(string s1, string s2)
{
string result = string.Empty;
//For multipication
bool Negative = false;
if(s1[0] == '-' && s2[0] == '-')
Negative = false;
else if(s1[0] == '-' || s2[0] == '-')
Negative = true;
char[] minusChar = {'-'};
string NewString;
NewString = s2.TrimStart(minusChar);
s2 = NewString;
NewString = s1.TrimStart(minusChar);
s1 = NewString;
List<string> resultList = new List<string>();
for(int i = s2.Length - 1; i >= 0; i--)
{
string multiplycation = string.Empty;
for (int j = s1.Length - 1; j >= 0; j--)
{
var augend = Convert.ToInt64(s1.Substring(j,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
long multiply = augend * addend;
// print(multiply);
multiplycation = multiply.ToString() + multiplycation;
}
//Adding zero at the end of the multiplication
for (int k = s2.Length - 1 - i; k > 0; k--)
{
multiplycation += "0";
}
resultList.Add(multiplycation);
}
for (int i = 1; i < resultList.Count; i++)
{
resultList[0] = Add(resultList[0],resultList[i]);
}
//Finally assigning if negative negative sign in front of the number
if(Negative)
result = resultList[0].Insert(0,"-");
else
result = resultList[0];
return result;
}
string Divide(string dividend, string divisor)
{
string result = string.Empty;
int remainder = 0;
int intNumberstoGet = divisor.Length;
int currentInt = 0;
int dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
int intDivisor = int.Parse(divisor);
while(currentInt < dividend.Length)
{
if(dividing == 0)
{
currentInt++;
result += "0";
}
else
{
while(dividing < intDivisor)
{
intNumberstoGet++;
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
}
if (dividing > 0)
{
remainder = dividing % intDivisor;
result += ((dividing - remainder) / intDivisor).ToString();
intNumberstoGet = 1;
if(currentInt < dividend.Length - 2)
currentInt += 2;
else
currentInt++;
if(currentInt != dividend.Length)
{
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
remainder *= 10;
dividing += remainder;
}
}
}
}
return result;
}
Here you go. Another example. It's 10 to 30 times faster than the accepted answer.
static string AddNumStr(string v1, string v2)
{
var v1Len = v1.Length;
var v2Len = v2.Length;
var count = Math.Max(v1Len, v2Len);
var answ = new char[count + 1];
while (count >= 0) answ[count--] = (char)((v1Len > 0 ? v1[--v1Len] & 0xF:0) + (v2Len>0 ? v2[--v2Len]&0xF : 0));
for (var i = answ.Length - 1; i >= 0; i--)
{
if (answ[i] > 9)
{
answ[i - 1]++;
answ[i] -= (char)10;
}
answ[i] = (char)(answ[i] | 48);
}
return new string(answ).TrimStart('0');
}
Below SO question has some interesting approaches. Though the answer is in Java, but you will surely get to know what needs to be done.
How to handle very large numbers in Java without using java.math.BigInteger
public static int[] addTwoNumbers(string s1, string s2)
{
char[] num1 = s1.ToCharArray();
char[] num2 = s2.ToCharArray();
int sum = 0;
int carry = 0;
int size = (s1.Length > s2.Length) ? s1.Length + 1 : s2.Length + 1;
int[] result = new int[size];
int index = size - 1;
int num1index = num1.Length - 1;
int num2index = num2.Length - 1;
while (true)
{
if (num1index >= 0 && num2index >= 0)
{
sum = (num1[num1index]-'0') + (num2[num2index]-'0') + carry;
}
else if(num1index< 0 && num2index >= 0)
{
sum = (num2[num2index]-'0') + carry;
}
else if (num1index >= 0 && num2index < 0)
{
sum = (num1[num1index]-'0') + carry;
}
else { break; }
carry = sum /10;
result[index] = sum % 10;
index--;
num1index--;
num2index--;
}
if(carry>0)
{
result[index] = carry;
}
return result;
}
When attemptiing to solve the below assignment :
Using the Arithmetic operators ( +,-,*,/) rearrange four fives to equal the number 1 to 10.
Example : 5/5+5-5 =1 ,5/5+5/5=2
I tried in C# without using Linq (I don't know how to proceed further)
public void GetDetails()
{
char[] sym = new char[] { '+', '-', '/', '*' };
int[] AOf5 = new int[] { 5, 5, 5, 5 };
for (int i = 0; i <4; i++)
{
for (int j = 0; j <4; j++)
{
for (int k = 0; k <4; k++)
{
for (int l = 0; l < 4; l++)
{
int result1 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
AOf5[2] + sym[k] + AOf5[3];
int result2 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
AOf5[2] + sym[l] + AOf5[3];
int result3 = AOf5[0] + sym[i] + AOf5[1] +
sym[k] + AOf5[2] + sym[l] + AOf5[3];
....
....
}
}
}
}
}
I am unable to complete it without linq and using linq.Expecting you help.
Applying left-to-right (no precedence), I can get:
1: ((5+5)-5)/5
2:
3: ((5+5)+5)/5
4: ((5*5)-5)/5
5: ((5-5)*5)+5
6: ((5*5)+5)/5
7: ((5+5)/5)+5
8:
9:
10: ((5+5)+5)-5
With (edit: oops - the "no div" stuff was unnecessary):
var operators = new[] {
new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
};
var options = from i in Enumerable.Range(1, 10)
select new {i, op=(
from op1 in operators
let v1 = op1.Func(5,5)
from op2 in operators
let v2 = op2.Func(v1, 5)
from op3 in operators
let v3 = op3.Func(v2,5)
where v3 == i
select "((5" + op1.Name + "5)" + op2.Name + "5)"
+ op3.Name + "5").FirstOrDefault()};
foreach (var opt in options)
{
Console.WriteLine(opt.i + ": " + opt.op);
}
I did it in a primitive way which I am not sure if the answer is correct. It is easier done in a spreadsheet though. Basically I modified linqfying's codes to generate codes.
Here is it:
public static void GetDetails()
{
int ctr = 0;
char[] sym = new char[] { '+', '-', '/', '*' };
string num = "5";
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 4; k++)
{
for (int l = 0; l < 4; l++)
{
ctr++;
string str = num + sym[i] + num + sym[j] + num + sym[k] + num;
Console.WriteLine("res = " + str + "; ");
Console.WriteLine("if(res>=1 && res<=10)");
Console.WriteLine("Console.WriteLine(\"" + str + "\");");
}
}
}
}
//Console.WriteLine("Total:" + ctr.ToString());
}
It generates 256 sets of operations which I output to a text file, copied and pasted them into a new method:
public static void runit()
{
float res = 0;
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
res = 5+5+5+5;
if (res >= 1 && res <= 10)
Console.WriteLine("5+5+5+5");
//......
//......
//......
//......
res = 5*5*5*5;
if (res >= 1 && res <= 10)
Console.WriteLine("5*5*5*5");
}
And run it again which I get 76 non-unqiue operations which fits between 1 and 10.
And 19 unique ones here (left to right operations only):
5*5/5/5
5*5/5+5
5/5*5/5
5/5*5+5
5/5/5+5
5/5+5/5
5/5+5-5
5/5-5+5
5+5*5/5
5+5/5*5
5+5/5/5
5+5/5-5
5+5+5-5
5+5-5/5
5+5-5+5
5-5/5/5
5-5/5+5
5-5+5/5
5-5+5+5
I'm sure someone can come out with something more creative :P
To add:
I realised after matching with Marc's answer, the initial loops didn't cover all permutations, my answers ain't gonna be right. But since I already spent quite some time, I'll let it stay. :P
The only missing cases in Marc's solution are the ones with operation precedence like in: 5/5+5/5. I added them in an union and here is the correct query.
Marc, if you update your answer with the code below (if you think it's correct) i'll delete this answer:
var operators = new[] {
new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
};
var options = from i in Enumerable.Range(1, 10)
select new
{
i,
op = (
from op1 in operators
let v1 = op1.Func(5, 5)
from op2 in operators
let v2 = op2.Func(v1, 5)
from op3 in operators
let v3 = op3.Func(v2, 5)
where v3 == i
select "((5" + op1.Name + "5)" + op2.Name + "5)"
+ op3.Name + "5")
.Union(
//calculate 2 operations (the left and the right one),
//then operate them together.
from op1 in operators
let v1 = op1.Func(5, 5)
from op2 in operators
let v2 = op2.Func(5, 5)
from op3 in operators
let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2)
where v3 == i
select "(5" + op1.Name + "5)" + op2.Name + "(5"
+ op3.Name + "5)"
).FirstOrDefault()
};
foreach (var opt in options)
{
Console.WriteLine(opt.i + ": " + opt.op);
}
EDIT:
A couple words about let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2): this is an awfully working way to avoid divisions by 0 (which can occur, because you can divide by (5-5)).
I am pretty sure you can filter it in a better way but i left it to enphasize that this problem CAN occur.
Assuming you DON'T want to use LINQ, here is an approach to do an implementation. That said it is horribly unoptimized, and I'd recommend a much shorter LINQ implementation over it. (See: Marc Gravell's post.)
using System;
using System.Collections.Generic;
namespace MathIterator
{
class Program
{
static readonly int[] _inputs = new int[] { 5, 5, 5, 5 };
static readonly char[] _operations = new char[] { '+', '-', '*', '/' };
static Dictionary<int, List<string>> _calculations = new Dictionary<int, List<string>>();
static void Main(string[] args)
{
StartPermutation();
PrintResults();
}
static void StartPermutation()
{
if (_inputs.Length > 0)
Permute(1 /*index*/, _inputs[0], _inputs[0].ToString());
}
static void Permute(int index, int result, string computation)
{
if (index == _inputs.Length)
{
if (!_calculations.ContainsKey(result))
{
_calculations[result] = new List<string>();
}
_calculations[result].Add(computation);
}
else
{
foreach (char operation in _operations)
{
string nextComputation = String.Format("({0} {1} {2})",computation, operation, _inputs[index]);
int nextResult = result;
switch (operation)
{
case '+':
nextResult += _inputs[index];
break;
case '-':
nextResult -= _inputs[index];
break;
case '*':
nextResult *= _inputs[index];
break;
case '/':
nextResult /= _inputs[index];
break;
}
Permute(
index + 1,
nextResult,
nextComputation);
}
}
}
static void PrintResults()
{
for (int i = 1; i <= 10; ++i)
{
if (_calculations.ContainsKey(i))
{
Console.WriteLine("Found {0} entries for key {1}", _calculations[i].Count, i);
foreach (string calculation in _calculations[i])
{
Console.WriteLine(i + " = " + calculation);
}
}
else
{
Console.WriteLine("No entry for key: " + i);
}
}
}
}
}
Here is another implementation. This one follows order of precedence. Again, I do not recommend solving it like this. Even more-so now given the wide dash hacks (to distinguish them from minus signs), but it does seem to work.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace MathIterator
{
class Program
{
static readonly int[] _inputs = new[] { 5, 5, 5, 5 };
//HUGE hack, the '–' is a wide dash NOT a hyphen.
static readonly char[][] _operationLevels = new[] { new[] { '*', '/' }, new[] { '+', '–' } };
static List<string> _calculations = new List<string>();
static Dictionary<int, List<string>> _results = new Dictionary<int, List<string>>();
static void Main(string[] args)
{
StartPermutation();
StartEvaluateCalculations();
PrintResults();
}
static void StartPermutation()
{
if (_inputs.Length > 0)
Permute(1 /*index*/, _inputs[0].ToString());
}
static void Permute(int index, string computation)
{
if (index == _inputs.Length)
{
_calculations.Add(computation);
}
else
{
foreach (char[] operationLevel in _operationLevels)
{
foreach (char operation in operationLevel)
{
string nextComputation = String.Format("{0} {1} {2}", computation, operation, _inputs[index]);
Permute(
index + 1,
nextComputation);
}
}
}
}
static void StartEvaluateCalculations()
{
foreach (string calculation in _calculations)
{
int? result = EvaluateCalculation(calculation);
if (result != null)
{
int intResult = (int) result;
if (!_results.ContainsKey(intResult))
{
_results[intResult] = new List<string>();
}
_results[intResult].Add(calculation);
}
}
}
static int? EvaluateCalculation(string calculation)
{
foreach (char[] operationLevel in _operationLevels)
{
string[] results = calculation.Split(operationLevel, 2);
if (results.Length == 2)
{
int hitIndex = results[0].Length;
Regex firstDigit = new Regex(#"^ -?\d+");
Regex lastDigit = new Regex(#"-?\d+ $");
string firstMatch = lastDigit.Match(results[0]).Value;
int arg1 = int.Parse(firstMatch);
string lastMatch = firstDigit.Match(results[1]).Value;
int arg2 = int.Parse(lastMatch);
int result = 0;
switch (calculation[hitIndex])
{
case '+':
result = arg1 + arg2;
break;
//HUGE hack, the '–' is a wide dash NOT a hyphen.
case '–':
result = arg1 - arg2;
break;
case '*':
result = arg1 * arg2;
break;
case '/':
if ((arg2 != 0) && ((arg1 % arg2) == 0))
{
result = arg1 / arg2;
break;
}
else
{
return null;
}
}
string prePiece = calculation.Remove(hitIndex - 1 - arg1.ToString().Length);
string postPiece = calculation.Substring(hitIndex + 1 + lastMatch.ToLower().Length);
string nextCalculation = prePiece + result + postPiece;
return EvaluateCalculation(nextCalculation);
}
}
return int.Parse(calculation);
}
static void PrintResults()
{
for (int i = 1; i <= 10; ++i)
{
if (_results.ContainsKey(i))
{
Console.WriteLine("Found {0} entries for key {1}", _results[i].Count, i);
foreach (string calculation in _results[i])
{
Console.WriteLine(i + " = " + calculation);
}
}
else
{
Console.WriteLine("No entry for key: " + i);
}
}
}
}
}
Here's a solution which is completely LINQ based (method-syntax) and late-evaluating, which handles all permutations (not only left-to-righ):
static void Main()
{
var solution = PermuteLength(4)
.Where(p => Decimal.Floor(p.Value) == p.Value)
.Where(p => p.Value <= 10 && p.Value >= 0)
.OrderBy(p => p.Value);
foreach (var p in solution)
{
Console.WriteLine(p.Formula + " = " + p.Value);
}
}
public static Operator[] Operators = new[]
{
new Operator {Format = "({0} + {1})", Function = (x, y) => x + y},
new Operator {Format = "({0} - {1})", Function = (x, y) => x - y},
new Operator {Format = "({1} - {0})", Function = (x, y) => y - x},
new Operator {Format = "({0} * {1})", Function = (x, y) => x * y},
new Operator {Format = "({0} / {1})", Function = (x, y) => y == 0 ? 0 : x / y},
new Operator {Format = "({1} / {0})", Function = (x, y) => x == 0 ? 0 : y / x},
};
public static IEnumerable<Permutation> BasePermutation = new[] { new Permutation {Formula = "5", Value = 5m} };
private static IEnumerable<Permutation> PermuteLength(int length)
{
if (length <= 1)
return BasePermutation;
var result = Enumerable.Empty<Permutation>();
for (int i = 1; i <= length / 2; i++)
result = result.Concat(Permute(PermuteLength(i), PermuteLength(length - i)));
return result;
}
private static IEnumerable<Permutation> Permute(IEnumerable<Permutation> left, IEnumerable<Permutation> right)
{
IEnumerable<IEnumerable<IEnumerable<Permutation>>> product = left.Select(l => right.Select(r => ApplyOperators(l, r)));
var aggregate =
product.Aggregate(Enumerable.Empty<IEnumerable<Permutation>>(), (result, item) => result.Concat(item)).
Aggregate(Enumerable.Empty<Permutation>(), (result, item) => result.Concat(item));
return aggregate;
}
private static IEnumerable<Permutation> ApplyOperators(Permutation left, Permutation right)
{
return Operators.Select(o => new Permutation
{
Formula = string.Format(o.Format, left.Formula, right.Formula),
Value = o.Function(left.Value, right.Value)
});
}
public struct Permutation
{
public string Formula;
public decimal Value;
}
public struct Operator
{
public string Format;
public Func<decimal, decimal, decimal> Function;
}
Known problems:
Some solutions are duplicate,
Doesn't handle division-by-zero very well, so some wrong answers (I've assumed anything divided by zero = 0)
Edit:
A part of result:
((5 / 5) / (5 / 5)) = 1
((5 / 5) + (5 / 5)) = 2
((5 + (5 + 5)) / 5) = 3
(5 - ((5 + 5) / 5)) = 3
(((5 * 5) - 5) / 5) = 4
(5 + (5 * (5 - 5))) = 5
(5 - (5 * (5 - 5))) = 5
(5 + ((5 - 5) / 5)) = 5
(5 - ((5 - 5) / 5)) = 5