Linq Arithemetic Operator combinations - c#

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

Related

string with quotes from database, cannot do interpolation

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:

Convert rule condition to rule list

I have a string which are combination of rules which I have to extract into array. AND condition are seperated by commas while OR move to next array index below are some condtion I am trying
(1 AND 2) AND (3 AND 4) => ["1,2,3,4"]
1 OR 2 => ["1","2"]
(1 OR (2 AND 3)) AND 4 => ["1,4","2,3,4"]
(1 OR 2) OR (3 OR 4) => ["1","2","3","4"]
I have tried the below approach is there a better approach than this.
static void Main(string[] args)
{
string input = "4 AND (1 OR (2 AND 3))";
List<string> output = new List<string>();
string inputTmp = input.Replace("(", "")
.Replace(")", "")
.Replace(" AND ", ",");
if (inputTmp.Contains("OR"))
{
List<string> orOutput = new List<string>();
List<List<string>> cmbOutput = new List<List<string>>();
char splitChar = ' ';
if (input.Contains(")) AND ((")) { inputTmp = input.Replace(")) AND ((", "&"); splitChar = '&'; }
else { if (input.Contains(")) AND ")) { inputTmp = input.Replace(")) AND ", "&"); splitChar = '&'; } }
if (input.Contains(")) OR ((")) { inputTmp = input.Replace(")) OR ((", "|"); splitChar = '|'; }
else { if (input.Contains(")) OR ")) { inputTmp = input.Replace(")) OR ", "|"); splitChar = '|'; } }
if (splitChar != ' ')
{
foreach (var item in inputTmp.Split(splitChar))
{
orOutput.Add(item.Replace("(", "").Replace(")", "").Replace(" AND ", ","));
}
}
else
{
orOutput.Add(input.Replace("(", "").Replace(")", "").Replace(" AND ", ","));
}
foreach (var item in orOutput)
{
List<string> lcOutput = new List<string>();
foreach (var oritem in item.Replace(" OR ", "|").Split('|'))
{
lcOutput.Add(oritem);
}
cmbOutput.Add(lcOutput);
}
if (cmbOutput.Count > 1 && splitChar == '&')
{
for (int i = 0; i < cmbOutput[0].Count; i++)
{
for (int j = 0; j < cmbOutput[1].Count; j++)
{
output.Add(cmbOutput[0][i] + "," + cmbOutput[1][j]);
}
}
}
else
{
foreach (var item in cmbOutput)
{
foreach (var initem in item) { output.Add(initem); }
}
}
}
else
{
output.Add(inputTmp);
}
output.ForEach(o => { Console.WriteLine(o); });
Console.ReadLine();
}
I've created a method that I hope meets your needs. It parses the given expression recursively.
Source code
public static string Parse(string s)
{
return '"' + InnerParse(s).Replace(";", "\",\"") + '"';
}
private static string InnerParse(string s)
{
int pos;
while ((pos = s.IndexOf('(')) != -1)
{
int count = 1;
int nextPos = pos;
while (count != 0)
{
nextPos = s.IndexOfAny(new[] { ')', '(' }, nextPos + 1);
if (nextPos == -1 || nextPos >= s.Length)
throw new ApplicationException(); // Unpaired parentheses
count = s[nextPos] == '(' ? count + 1 : count - 1;
}
s = (pos != 0 ? s.Substring(0, pos - 1) : String.Empty)
+ InnerParse(s.Substring(pos + 1, nextPos - pos - 1)) // Recursion
+ s.Substring(nextPos + 1);
}
string[] operands = s.Split(new[] { "AND", "OR" }, StringSplitOptions.None);
if (operands.Length != 2)
throw new ApplicationException(); // Count of operands != 2
string op1 = operands[0].Trim();
string op2 = operands[1].Trim();
// If operator is OR
if (s.Contains("OR"))
return op1 + ';' + op2;
// If operator is AND
string[] op1s = op1.Split(';');
string[] op2s = op2.Split(';');
string[] ret = new string[op1s.Length * op2s.Length];
int i = 0;
foreach (string s1 in op1s)
foreach (string s2 in op2s)
ret[i++] = s1 + ',' + s2;
return String.Join(";", ret);
}
Usage example
Console.WriteLine(Parse("(1 OR (2 AND 3)) AND 4"));
Restrictions
Two operators are recognized: AND, OR.
Operators are case-sensitive.
Operators have exactly two operands.
Operands cannot contain a double-quote " or a semicolon ;.

how to convert a string to a mathematical expression programmatically

I am a beginner at C#. I am facing a problem while converting a string to a mathematical expression. I have a UI where user can create formula using random formula field. And in another UI user will give input of those formula field.
like for example at first time the formula may be (a+b)^n and another the formula may be ((a+b+c)^n+b).
In my calculation UI for the first time user will give input for a,b,n and for 2nd formula user will give input for a,b,c,n. Can anyone please help me about how to get the result for both of the formula programmatic-ally? Thanks in advance
This is how it should be done:
public class StringToFormula
{
private string[] _operators = { "-", "+", "/", "*","^"};
private Func<double, double, double>[] _operations = {
(a1, a2) => a1 - a2,
(a1, a2) => a1 + a2,
(a1, a2) => a1 / a2,
(a1, a2) => a1 * a2,
(a1, a2) => Math.Pow(a1, a2)
};
public double Eval(string expression)
{
List<string> tokens = getTokens(expression);
Stack<double> operandStack = new Stack<double>();
Stack<string> operatorStack = new Stack<string>();
int tokenIndex = 0;
while (tokenIndex < tokens.Count) {
string token = tokens[tokenIndex];
if (token == "(") {
string subExpr = getSubExpression(tokens, ref tokenIndex);
operandStack.Push(Eval(subExpr));
continue;
}
if (token == ")") {
throw new ArgumentException("Mis-matched parentheses in expression");
}
//If this is an operator
if (Array.IndexOf(_operators, token) >= 0) {
while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek())) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
operatorStack.Push(token);
} else {
operandStack.Push(double.Parse(token));
}
tokenIndex += 1;
}
while (operatorStack.Count > 0) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
return operandStack.Pop();
}
private string getSubExpression(List<string> tokens, ref int index)
{
StringBuilder subExpr = new StringBuilder();
int parenlevels = 1;
index += 1;
while (index < tokens.Count && parenlevels > 0) {
string token = tokens[index];
if (tokens[index] == "(") {
parenlevels += 1;
}
if (tokens[index] == ")") {
parenlevels -= 1;
}
if (parenlevels > 0) {
subExpr.Append(token);
}
index += 1;
}
if ((parenlevels > 0)) {
throw new ArgumentException("Mis-matched parentheses in expression");
}
return subExpr.ToString();
}
private List<string> getTokens(string expression)
{
string operators = "()^*/+-";
List<string> tokens = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in expression.Replace(" ", string.Empty)) {
if (operators.IndexOf(c) >= 0) {
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
sb.Length = 0;
}
tokens.Add(c);
} else {
sb.Append(c);
}
}
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
}
return tokens;
}
}
Call the class and method like this:
string formula = "type your formula here"; //or get it from DB
StringToFormula stf = new StringToFormula();
double result = stf.Eval(formula);
There are plenty methods for formula evaluation,
take a look. Just take your input, replace a, b, n chars in your string to values provided by user and resolve equation with one of methods mentioned.
i think this is the solution
Expression e = new Expression("((a+b+c)^n+b)");
e.Evaluate();
string input= "(12 + 4 * 6) * ((2 + 3 * ( 4 + 2 ) ) ( 5 + 12 ))";
string str4 = "(" + input`enter code here`.Replace(" ", "") + ")";
str4 = str4.Replace(")(", ")*(");
while (str4.Contains('('))
{
string sub1 = str4.Substring(str4.LastIndexOf("(") + 1);
string sub = sub1.Substring(0, sub1.IndexOf(")"));
string sub2 = sub;
string str21 = sub2.Replace("^", "~^~").Replace("/", "~/~").Replace("*", "~*~").Replace("+", "~+~").Replace("-", "~-~");
List<string> str31 = str21.Split('~').ToList();
while (str31.Count > 1)
{
while (str31.Contains("*"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "*")
{
val = Convert.ToDouble(str31[i - 1]) * Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("/"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "/")
{
val = Convert.ToDouble(str31[i - 1]) / Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("+"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "+")
{
val = Convert.ToDouble(str31[i - 1]) + Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("-"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "-")
{
val = Convert.ToDouble(str31[i - 1]) - Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
}
str4 = str4.Replace("(" + sub + ")", str31[0].ToString());
}
string sum = str4;
The most structural approach which comes to my mind would be to define a grammar consisting out of operator symbols (which are apparently +,-,*,/ and ^ in your case) and operands; then, if a derivation of the input in the defined grammar exists, the derivation basically is the expression tree which can then be traversed recursively while the operators are directry translated to the actual operations. I admit that the description is a bit vague, but good parsing can be a bit difficult. Perhaps a look at LL parser can help a bit.
convert String To Mathematical Expression
var s3 = "3 - 4 + 5 * 9"
var s4 = NSExpression(format: s3).expressionValue(with: nil, context: nil) as! Double // 44.0
Answer : 44

how to code for checkbox to get pattern output explain below

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();
}

project euler 22 using c#

I am solving the same problem as here Project Euler #22 Python, 2205 points missing?, but I am using C#. I can't find the mistake. Here is my code:
class Program
{
static List<string> pole;
static string SaveName(StreamReader reader)
{
int znak = reader.Read();
string jmeno = "";
while ((znak < 'A') || (znak > 'Z'))
{
znak = reader.Read();
}
while (znak != ',')
{
jmeno = jmeno + (char) znak;
znak = reader.Read();
if (znak == 34) break;
}
return jmeno;
}
static void SaveNamesIntoList()
{
StreamReader reader = new StreamReader(#"../../../names.txt");
while (reader.Read() != ';')
{
pole.Add(SaveName(reader));
}
}
static void Main(string[] args)
{
pole = new List<string>();
SaveNamesIntoList();
pole.Sort();
int sum = 0;
int sum_word = 0;
string name = "";
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum += (sum_word * (i+1));
}
Console.WriteLine(sum);
}
}
Thanks for any answer:)
Ther reason why you have different result is than Czech language has specific letter 'CH' whitch is after 'H' so in alfabetical order without using right culture you can have sometring like this
aaa
bbb
ccc
czz
ddd
cha
There are a few issues here. You don't check if the reader reached the end of stream - you have to check if the Read returned -1. If it did - it's the end of the file. On top of that, you don't dispose the reader...
Then, as Cedric noted in the comments, you haven't really sorted the list, hence the result is wrong even after changing it to:
using (var reader = new StreamReader("names.txt"))
{
while (reader.Read() != -1)
{
pole.Add(SaveName(reader));
}
}
What you need to do is add this line (which is a bit wasteful in general, but I'll get to that in a sec):
pole = pole.OrderBy(x => x).ToList(); //<<----- this one
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum2 += (sum_word*(i + 1));
}
And the result is 871198282, which should be correct - at least that's what the people are saying in the linked question.
Even then, might I suggest an easier way of solving that whole problem:
var scores = Enumerable.Range('A', 'Z' - 'A' + 1)
.Select((i, ch) => new { Character = (char) i, Weight = ch + 1 })
.ToDictionary(key => key.Character, val => val.Weight);
var sum = File.ReadAllText("names.txt")
.Split(',')
.Select(x => x.Trim('"'))
.OrderBy(x => x)
.Select((x, i) => (i + 1)*x.Select(y => scores[y]).Sum())
.Sum();
Here's a version using Linq.
void Main()
{
var file = #"C:\...location.of.file...\p022_names.txt";
using (var reader = new StreamReader(file, Encoding.UTF8))
{
NameScore(reader.ReadToEnd().Replace("\"",string.Empty).Split(new[]{','})).Dump();
}
}
private long NameScore(string[] names)
{
return names.OrderBy(o => o)
.Select((l, i) => { return l.ToUpper().ToCharArray().Sum(s => (int)s - 64) * (i + 1);})
.Sum(s => s);
}

Categories

Resources