Compacting multiple similar if statements in C# - c#

I would like to make some code for a game a little more compact. Here is the original.
if (killPosX != 0) // float x position you would like the object to be destroyed at
{
killX = true; // automatically makes the value of killX true
}
if (killPosY != 0) // float y position you would like the object to be destroyed at
{
killY = true; // automatically makes the value of killY true
}
if (killPosT != 0) // float position in time you would like the object to be destroyed at
{
killT = true; // automatically makes the value of killT true
}
And I want to turn it into something like this:
if ([killPosX, killPosY, killPosT] != 0)
{
[killPosX, killPosY, killPosT] = true;
}
How would I do that?

if (killPosX != 0)
{
killX = true;
}
Could be translated as follow
killX = (killPosX != 0) ? true : killX;
Or more simply
killX |= killPosX != 0;
if (killPosX != 0)
{
killX = true;
}
else
{
killX = false;
}
Could be translated as follow
killX = (killPosX != 0) ? true : false;
Or more simply
killX = killPosX != 0;
But since comparing floats using == or != is not advised, I would go for:
killX |= !Mathf.Approximately( killPosX, 0 );
killY |= !Mathf.Approximately( killPosY, 0 );
killT |= !Mathf.Approximately( killPosT, 0 );
AFAIK, there is no built-in syntax similar to what you wrote in order to achieve what you want.

I'm not sure if this applies to what you're working on (and there may be a better way in Unity), but it seems to me that one way to do it would be to make the KillN properties calculated on the value of their corresponding KillPosN property:
public class SomeClass
{
public float KillPosX { get; set; }
public float KillPosY { get; set; }
public float KillPosT { get; set; }
// Values are based on the related property values and cannot be set directly
public bool KillX => !IsRoughlyZero(KillPosX);
public bool KillY => !IsRoughlyZero(KillPosY);
public bool KillT => !IsRoughlyZero(KillPosT);
private static bool IsRoughlyZero(float input)
{
// Use a tolerance for comparing floating point numbers to 0
return Math.Abs(input) < .0000001;
}
}

I can't think of a way to do it as you suggest but it might be a little neater and more compact to use a variation of the approach hellium suggested:
public void fnc(ref bool t1, float t2) { t1 |= !Mathf.Approximately( t2, 0 ); }
fnc(ref KillX, KillPosX);
fnc(ref KillY, KillPosY);
fnc(ref KillT, KillPosT);
You could of course wrap it in a method which uses arrays as parameters but unless you need a generic way to do this for variable sized arrays, the setup cost is bulkier than just using discrete calls.

Related

Modifying value of array after finding element with LINQ query

I want to change a value in an array that holds a struct:
SitSpot[] _spots = new SitSpot[4];
The struct fields are:
struct SitSpot
{
public SitSpot(Transform spot, bool isOccupied, int id)
{
IsOccupied = isOccupied;
Spot = spot;
Id = id;
}
public bool IsOccupied;
public Transform Spot;
public int Id;
}
However, when accessing the array element and trying to modify it, the original array element remains unchanged
SitSpot spot = _spots.Where(x => x.IsOccupied != true).OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position)).FirstOrDefault();
spot.IsOccupied = true;
So it is necessary to find the index of the array element by to modify specified value:
SitSpot spot = _spots
.Where(x => x.IsOccupied != true)
.OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position))
.FirstOrDefault();
spot.IsOccupied = true;
int i = Array.FindIndex(_spots, x => x.Id == spot.Id);
_spots[i] = spot;
My question is, can I access the element inside the array and modify it directly rather than changing the value and reassigning it?
The best choice in your situation seems not to use LINQ. I propose following
static class Extensions
{
public static void SetOccupied(this SitSpot[] spots, Driver driver)
{
int index = -1;
int distance = int.MaxValue;
for (int i = 0; i < spots.Length; i++)
{
if (spots[i].IsOccupied != true)
{
var distance2 = Vector3.Distance(spots[i].Spot.position,
driver.transform.position);
if (distance >= distance2)
{
distance = distance2;
index = i;
}
}
}
if (index != -1)
{
spots[index].IsOccupied = true;
}
}
}

How to call a function when 3 out of 7 boolean values evaluates to true

I am trying to create a quest giving system this way:
There are 7 boolean values and a method that should be called only when any 3 out of the 7 boolean values evaluates to true. What is the most efficient/better way to accomplish this task? I am a bit new to programming so here is a code snippet:
private bool a;
private bool b;
private bool c;
private bool d;
private bool e;
private bool f;
private bool g;
private void Start() {
//How do I call TheMethod() when any 3 of the 7 booleans evaluates to true?
}
private void TheMethod() {
//DO SOMETHING
}
Do I have to create multiple if conditions that checks this?
using array or list with Linq could simplify your test:
using System.Linq;
using System.Collections.Generic;
// using array a = trig[0], b = trig[1] and so on
private bool[] trig = new bool[7] { true, false, false, true, true, false, true };
//or using list a = trig1[0], b = trig1[1] and so on
private List<bool> trig1 = new List<bool>{ true, false, false, true, true, false, true };
void Start(){
//same syntax array or list
trig[0] = false; // change value for fun
if(trig.Count(p => p) ==3)// result = 3
{
TheMethod();
}
trig1[0] = false;// change value for fun
if(trig1.Count(p => p) ==3) //result = 3
{
TheMethod();
}
//if you want to keep your boolean variable outside a collection
//you add your boolean variables to list (or array)
var list = new List<Bool>() {a,b,c,d,e,f,g};
if (list.Count(p => p) == 3)
{
TheMethod();
}
}
The most efficient way is to change how you do this; consider instead:
private uint bits;
and use bit math to detect individual flags, for example:
private bool A => (values & 1) != 0;
private bool B => (values & 2) != 0;
private bool C => (values & 4) != 0;
// etc, powers of 2
Now you can use
var setBits = BitOperations.PopCount(bits);
and test that, i.e. if (setBits == 3). This then uses a CPU intrinsic when possible, falling back to a decently-optimized software implementation otherwise.
Without the need for an array you could do
private void Start()
{
if(Exactly3True())
{
TheMethod();
}
}
private void TheMethod()
{
//DO SOMETHING
}
private bool Exactly3True()
{
var checkSum = (a ? 1 : 0)
+ (b ? 1 : 0)
+ (c ? 1 : 0)
+ (d ? 1 : 0)
+ (e ? 1 : 0)
+ (f ? 1 : 0)
+ (g ? 1 : 0);
return checkSum == 3;
}
(see ternary operator ?)
not that this is the best thing regarding maintainability ;)
If you are using Unity, you can try
[SerializeField]
private bool[] values;
And attach this code to any existing GameObject, you can set the length of values in the inspecter. Set it to 7, and
private void Start()
{
int boolCount = 0;
foreach (var b in values)
{
if (b == true) boolCount++;
if (boolCount == 3)
{
TheMethod();
break;
}
}
}
It's just example code, but using Unity's serialize feature will much more increase the readability of your code.

Check List order is wrong or right , How to make code clear

I want to check list order is right or worng , And my solution be here.
it worked , But it look dirty & stupid , Have any better soultion can do that ?
I add two example to explain is case .
public enum HI
{
A,
B,
C
}
public class Test : MonoBehaviour
{
public void TestOroder()
{
// check hiList order ----> A >B >C
List<HI> hiList = new List<HI>() { HI.A, HI.B, HI.B, HI.B, HI.C , HI.C , HI.C };
//right
bool isRight = FindWorngOrder(hiList);
// check hiList order ----> A >B >C
List<HI> hiList2 = new List<HI>() { HI.A, HI.B, HI.C, HI.A ,HI.B, HI.B, HI.C };
//worng
bool isRight2 = FindWorngOrder(hiList);
}
public bool FindWorngOrder(List<HI> hiList)
{
bool haveWorngOrder;
for (int i = 0; i < hiList.Count - 1; i++)
{
HI current = hiList[i];
HI next = hiList[i + 1];
if (current == HI.C && next == HI.A ||
current == HI.C && next == HI.B)
{
return true;
}
if (current == HI.C && next == HI.B)
{
return true;
}
}
return false;
}
}
I'd suggest using:
public bool IsInTheSamerOrder(IEnumerable<HI> hiList)
{
return hiList.SequenceEqual(hiList.OrderBy(z => z));
}
It is similar to your answer, but slightly shorter and doesn't need the explicit List.
by #mjwills answer
public bool FindWorngOrder(List<HI> hiList)
{
List<HI> orderd = hiList.ToList();
orderd.Sort();
return orderd.SequenceEqual(hiList);
}

Complex Computed Column in EF

I have an object that has a calculation field; The calculation formula is too complex, and it have to check some condition, and load some data from another objects (have to join with other tables).
This is my Object:
public class LoadAndExitPermit : Master, IColorSource
{
private int? _ladingBillId;
[DataMember]
public virtual int? LadingBillID
{
get { return _ladingBillId; }
set { SetPropertyValue(ref _ladingBillId, value, "LadingBillID"); }
}
.
. {lots of Properties)
.
[DataMember]
public virtual ICollection<LoadAndExitPermitDocumentDetail> LoadAndExitPermitDocumentDetails { get; set; }
The important part of my object is SumGoodsUnitPrice, and it's:
[NotMapped, DataMember]
Public decimal? SumGoodsUnitPrice
{
get
{
if (LoadAndExitPermitDetails == null || !LoadAndExitPermitDetails.Any())
{
return -1;
}
if (LoadAndExitPermitDetails.First().RequestDetail.OrderDetail == null)
{
decimal? sum = 0m;
foreach (var item in LoadAndExitPermitDetails)
{
decimal? tarrif = item.Good.GoodsTariffDetails.Where(g =>
g.Price > 0 && g.IsActive == true && g.GoodsTariff.GoodsTariffType.IsPublic == true && g.GoodsTariff.FromDate < Date)
.OrderByDescending(w => w.GoodsTariff.FromDate).Select(c => c.Price).FirstOrDefault();
if (tarrif != null)
{
sum += ((item.Quantity ?? 0) * (1.09m * (tarrif))) ?? 0m;
}
else
{
decimal? lastTariff = item.Good.GoodsTariffDetails.Where(x => x.Price > 0 && x.IsActive == true
&& x.GoodsTariff.FromDate < Date).OrderByDescending(w => w.GoodsTariff.FromDate).Select(c => c.Price).FirstOrDefault() ?? 0m;
sum += ((item.Quantity ?? 0) * (1.09m * (lastTariff))) ?? 0;
}
}
return sum;
}
var z = LoadAndExitPermitDetails.Sum(l => (l.Quantity ?? 0) * (1.09m * (l.RequestDetail.OrderDetail.Quantity == 0 ? 0 : (l.RequestDetail.OrderDetail.Price / l.RequestDetail.OrderDetail.Quantity) ?? 0)));
return z;
}
private set
{
}
}
I have some Issues:
I can't use Projection, I have two reasons: first readability of the code and the 2th one is my project structure doesn't allow me to use projected query.
We use database first method and this field is not in database, because its calculated field.
We deal with a large database and I can't Include (join) all tables i need, so i prefer to use SQL service side query to calculate it for me.
We can't use Stored Procedure Or View, Because we have lots of this kind of columns, and we need to use dynamic query for dynamic filters.
The performance of query is very important for us.
I would appropriate if anyone can help me.
If I where you, I add a view that calculate this field on the server and use for queries this view. This is compatible with CQRS architectural pattern.

Asp.Net : Extended range validation

I'm using Asp.Net 2.0. I have a scenario where i need to check a user input against any of two ranges. For e.g. I need to check a textbox value against ranges 100-200 or 500-600. I know that i can hook up 2 Asp.Net RangeValidators to the TextBox, but that will try to validate the input against both the ranges, an AND condition,if you will. CustomValidator is an option, but how would I pass the 2 ranges values from the server-side. Is it possible to extend the RangeValidator to solve this particular problem?
[Update]
Sorry I didn't mention this, the problem for me is that range can vary. And also the different controls in the page will have different ranges based on some condition. I know i can hold these values in some js variable or hidden input element, but it won't look very elegant.
A CustomValidator should work. I'm not sure what you mean by "pass the 2 ranges values from the server-side". You could validate it on the server-side using a validation method like this:
void ValidateRange(object sender, ServerValidateEventArgs e)
{
int input;
bool parseOk = int.TryParse(e.Value, out input);
e.IsValid = parseOk &&
((input >= 100 || input <= 200) ||
(input >= 500 || input <= 600));
}
You will then need to set the OnServerValidate property of your CustomValidator to "ValidateRange", or whatever you happen to call it.
Is this the sort of thing you're after?
I do not believe this is possible using the standard RangeValidator control.
I did some searching and I believe your best solution is going to be to create your own CustomValidator control which you can include in your project to handle this scenario.
http://www.dotnetjunkies.ddj.com/Article/592CE980-FB7E-4DF7-9AC1-FDD572776680.dcik
You shouldn't have to compile it just to use it in your project, as long as you reference it properly.
You can use the RegularExpressionValidator with the ValidationExpression property set to
Edit: (whoops, 650 and 201 etc. were valid with the old pattern)
^(1\d{2}|200|5\d{2}|600)$
This will test the entered text for 100-200 and 500-600.
I extended the BaseValidator to achieve this. Its fairly simple once you understand how Validators work. I've included a crude version of code to demonstrate how it can be done. Mind you it's tailored to my problem(like int's should always be > 0) but you can easily extend it.
public class RangeValidatorEx : BaseValidator
{
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if (base.RenderUplevel)
{
string clientId = this.ClientID;
// The attribute evaluation funciton holds the name of client-side js function.
Page.ClientScript.RegisterExpandoAttribute(clientId, "evaluationfunction", "RangeValidatorEx");
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1High", this.Range1High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2High", this.Range2High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1Low", this.Range1Low.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2Low", this.Range2Low.ToString());
}
}
// Will be invoked to validate the parameters
protected override bool ControlPropertiesValid()
{
if ((Range1High <= 0) || (this.Range1Low <= 0) || (this.Range2High <= 0) || (this.Range2Low <= 0))
throw new HttpException("The range values cannot be less than zero");
return base.ControlPropertiesValid();
}
// used to validation on server-side
protected override bool EvaluateIsValid()
{
int code;
if (!Int32.TryParse(base.GetControlValidationValue(ControlToValidate), out code))
return false;
if ((code < this.Range1High && code > this.Range1Low) || (code < this.Range2High && code > this.Range2Low))
return true;
else
return false;
}
// inject the client-side script to page
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (base.RenderUplevel)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RangeValidatorEx", RangeValidatorExJs(),true);
}
}
string RangeValidatorExJs()
{
string js;
// the validator will be rendered as a SPAN tag on the client-side and it will passed to the validation function.
js = "function RangeValidatorEx(val){ "
+ " var code=document.getElementById(val.controltovalidate).value; "
+ " if ((code < rangeValidatorCtrl.Range1High && code > rangeValidatorCtrl.Range1Low ) || (code < rangeValidatorCtrl.Range2High && code > rangeValidatorCtrl.Range2Low)) return true; else return false;}";
return js;
}
public int Range1Low
{
get {
object obj2 = this.ViewState["Range1Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1Low"] = value; }
}
public int Range1High
{
get
{
object obj2 = this.ViewState["Range1High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1High"] = value; }
}
public int Range2Low
{
get
{
object obj2 = this.ViewState["Range2Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2Low"] = value; }
}
public int Range2High
{
get
{
object obj2 = this.ViewState["Range2High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2High"] = value; }
}
}

Categories

Resources