คุณมีเคล็ดลับทั่วไปเกี่ยวกับการเล่นกอล์ฟใน C # อย่างไร ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ C # (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
- ยืมมาจากความคิดของ Marcog;)
คุณมีเคล็ดลับทั่วไปเกี่ยวกับการเล่นกอล์ฟใน C # อย่างไร ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ C # (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
- ยืมมาจากความคิดของ Marcog;)
คำตอบ:
แทนที่จะ.ToString()
ใช้+""
สำหรับตัวเลขและประเภทอื่น ๆ ที่สามารถส่งไปยังสตริงได้อย่างปลอดภัย
.ToString() <-- 11 chars
+"" <-- 3 chars
(1+"").DoSomethingWith1String();
String.Concat(object)
แปลงเป็นสตริงว่างอย่างชัดเจน( ดูแหล่งอ้างอิง ) ไม่มี 'การคัดเลือกนักแสดงพื้นเมือง' เกิดขึ้นคุณสามารถแปลงอะไรเช่นนี้ได้ แต่ผลที่ได้อาจไม่เป็นประโยชน์ในบางกรณี! (แต่พฤติกรรมที่เป็นโมฆะอาจเป็นไปได้) object.ToString()
Concat
null
$"{n}"
ฉันตั้งใจวางโปรแกรมของฉันไว้namespace System
เพื่อที่ฉันจะได้สั้นลงในชั้นเรียนที่เฉพาะเจาะจง เปรียบเทียบ
using System;using M=System.Math;
ไปยัง
namespace System{using M=Math;
System
เนมสเปซเท่านั้น
using System;class P...
นอกจากนี้คุณยังสามารถเพียงแค่ทำ
using System;
เกี่ยวกับการมีนามแฝงสำหรับคลาสในเนมสเปซเดียวกันซึ่งสั้นกว่าที่ฉันแสดงไว้ที่นี่
using static System.Math;
ใน C # 6 (เพิ่มคุณสามารถใช้ฟังก์ชั่นเหล่านั้นราวกับว่าพวกเขาเป็นโลกอย่างแท้จริง - ไม่ได้อยู่ในชั้นเรียน) คำแนะนำดั้งเดิมอาจยังสั้นกว่าusing static
ถ้าคุณต้องการเข้าถึงหลายคลาส
static
คำหลักเพิ่มเติมมักจะยาวกว่าการประหยัดจากการออกจากM.
วิธีการโทร แต่ใช่มันเป็นตัวเลือก
ใช้var
สำหรับการประกาศและเริ่มต้นตัวแปร (เดี่ยว) เพื่อบันทึกอักขระบนประเภท:
string x="abc";
กลายเป็น
var x="abc";
int
แน่นอนว่าไม่จำเป็นต้องมีอนุภาค
var
ไม่สามารถมีผู้ประกาศหลายคนเช่นvar x="x",y="y";
เป็นไปไม่ได้
หากใช้ LINQ คุณสามารถส่งวิธีการโดยตรงไปที่Select
แทนที่จะทำแลมบ์ดา
ดังนั้นแทนที่จะ
foo.Select(x=>int.Parse(x))
คุณสามารถใช้ได้
foo.Select(int.Parse)
โดยตรง.
โปรดจำไว้ว่าโปรแกรมที่คอมไพล์ได้เล็กที่สุดใน C # คือ 29 ตัวอักษร:
class P
{
static void Main()
{
}
}
ดังนั้นเริ่มต้นด้วยการลบสิ่งนั้นออกจากความยาวของคุณ C # ไม่สามารถแข่งขันกับภาษาอื่นเมื่อพูดถึงการพิมพ์หรือการอ่านซึ่งเป็นหัวใจของ[code-golf]
ปัญหาส่วนใหญ่ดังนั้นอย่ากังวลไป ในฐานะนักกอล์ฟ C # คุณต้องแข่งขันกับภาษาจริงๆ
สิ่งอื่น ๆ ที่ควรทราบ:
if
คำสั่งทั้งหมดเป็นบรรทัดเดียวถ้าเป็นไปได้เพื่อที่จะลบวงเล็บAs a C# golfer, you're really competing against the language
เกี่ยวข้องอย่างไม่น่าเชื่อ
static int Main()
เช่นกันซึ่งจะเป็น 28 ตัวอักษร
return
บางสิ่งบางอย่าง
แทน
bool a = true;
bool b = false;
ทำ
var a=0<1;
var b=1<0;
หากคุณต้องการตัวแปรหลายตัวให้ใช้สิ่งนี้ (แนะนำโดย@VisualMelon )
bool a=0<1,b=!a;
bool a=0<1,b=!a;
สนับสนุนผู้ประกอบการที่ประกอบไปด้วยมากกว่าif
.. else
บล็อกที่เหมาะสม
ตัวอย่างเช่น:
if(i<1)
j=1;
else
j=0;
มีประสิทธิภาพมากขึ้น:
j=i<1?1:0;
var x = input ?? "";
(ฉันรัก coalesces ของฉัน)
i < 1
เป็นคำสั่งที่ซับซ้อนหรือเมื่อชื่อของj
มีความยาว IMO ก็ยังไม่สามารถถ่ายทอดผลข้างเคียงได้เป็นอย่างดี ในกรณีที่if (i < 1)
เป็นสิ่งที่ต้องการif (SendEmail(recipient))
ผลตอบแทนจริง / เท็จขึ้นอยู่กับความสำเร็จของผลข้างเคียงที่ฉันชอบถ้า / แล้วสัญกรณ์
j=i<1?1:0;
ก็เพียงพอแล้ว
คุณสามารถแทนที่ float
(ซึ่งเป็นชื่อแทนSystem.Single
) ด้วยการz
ใช้z=System.Single;
แล้วแทนที่z=System.Single;
ด้วยz=Single;
โดยการวางโปรแกรมในการ System
namespace (เช่นเดียวกับคำตอบของ Joey)
สิ่งนี้สามารถนำไปใช้กับประเภทค่าอื่น ๆ (ใช้สิ่งที่พวกเขาเป็นนามแฝง), structs และชั้นเรียน
หากคุณจำเป็นต้องใช้Console.ReadLine()
รหัสของคุณหลายครั้ง (ขั้นต่ำ 3 ครั้ง) คุณสามารถทำได้:
Func<string>r=Console.ReadLine;
แล้วก็ใช้
r()
แทน
()
จากบรรทัดแรก
auto r=Console.ReadLine;
ไม่ได้เหรอ
auto
เป็นC++
คำกริยา สำหรับvar
C#
สาเหตุที่ไม่สามารถทำได้เนื่องจากConsole.ReadLine
มีการโอเวอร์โหลดดังนั้นจำเป็นต้องระบุฟังก์ชันของลายเซ็นเพื่อบอกคอมไพเลอร์ว่าต้องการโอเวอร์โหลดใด
เมื่ออ่านแต่ละอักขระของอาร์กิวเมนต์บรรทัดคำสั่งแทนที่จะวนลูปขึ้นกับความยาวของสตริง:
static void Main(string[]a){
for(int i=0;i<a[0].Length;)Console.Write(a[0][i++]);
}
คุณสามารถบันทึกอักขระโดยใช้บล็อก try / catch เพื่อค้นหาจุดสิ้นสุด:
static void Main(string[]a){
try{for(int i=0;;)Console.Write(a[0][i++]);}catch{}
}
สิ่งนี้ใช้กับอาเรย์ใด ๆ ภายในอาเรย์เช่น:
string[]
int[][]
IList<IList<T>>
ใน C # 6 คุณสามารถใช้แลมบ์ดาเพื่อกำหนดฟังก์ชั่น:
int s(int a,int b)=>a+b;
สิ่งนี้สั้นกว่าการนิยามฟังก์ชั่นดังนี้:
int s(int a,int b){return a+b;}
แทนที่จะใช้:
Enumerable.Range(0,y).Select(i=>f(i))
จะได้รับการ Enumerable กับผลลัพธ์ของการทำงานf
สำหรับทุกคนint
ใน[0,y]
ที่คุณสามารถใช้
new int[y].Select((_,i)=>f(i))
หากคุณต้องการstring
หรืออะไรก็ตามที่ใช้Enumerable
ในโปรแกรมของคุณคุณสามารถใช้มันได้เช่นกัน
var s="I need this anyway";
s.Select((_,i)=>f(i))
หากคุณจำเป็นต้องใช้รหัสทั่วไปDictionary<TKey, TValue>
อย่างน้อยสองครั้งในรหัสของคุณคุณสามารถประกาศคลาสพจนานุกรมเช่นในตัวอย่างนี้:
class D:Dictionary<int,string>{}
แล้วก็ใช้
D d=new D{{1,"something"},{2,"something else"}};
แทนการทำซ้ำDictionary<int,string>
สำหรับทุก instantiation
using D = System.Collections.Generic.Dictionary<int,string>;
คุณสามารถใช้float
และdouble
ตัวอักษรเพื่อบันทึกไม่กี่ไบต์
var x=2.0;
var y=2d; // saves 1 byte
เมื่อคุณต้องการint
เลขคณิตเพื่อส่งคืน a float
หรือdouble
คุณสามารถใช้ตัวอักษรเพื่อบังคับการแปลง
((float)a+b)/2; // this is no good
(a+b)/2.0; // better
(a+b)/2f; // best
หากคุณเคยประสบกับสถานการณ์ที่ต้องโยนคุณสามารถบันทึกสองสามไบต์โดยใช้การคูณแทน
((double)x-y)/(x*y);
(x*1d-y)/(x*y); // saves 5 bytes
(x-y)*1d/x/y;
โปรดจำไว้ว่าที่ส่วนตัวหรือสาธารณะมีอยู่จริงเช่นต่อไปนี้:
class Default{static void Main()
เมื่อเทียบกับ
public class Default { public static void Main()
Main
ไม่จำเป็นต้องมีข้อโต้แย้งใด ๆ ในทางตรงกันข้ามกับ Java ตัวอย่างเช่น
สำหรับการแสดงออกแลมบ์ดาหนึ่งบรรทัดคุณสามารถข้ามเครื่องหมายวงเล็บและเครื่องหมายอัฒภาคได้ สำหรับนิพจน์ที่มีพารามิเตอร์เดียวคุณสามารถข้ามวงเล็บได้
แทน
SomeCall((x)=>{DoSomething();});
ใช้
SomeCall(x=>DoSomething);
SomeCall(DoSomething)
ดียิ่งขึ้นอีก
วนรอบ:
ประกาศตัวแปร:
int max;
for(int i=1;i<max;i++){
}
เป็น:
int max,i=1;
for(;i<max;i++){
}
และถ้าคุณต้องการหรือทำงานกับตัวแปร i เพียงครั้งเดียวคุณสามารถเริ่มต้นที่ -1 (หรือ 0 ขึ้นอยู่กับสถานการณ์ของลูป) และอินไลน์ที่เพิ่มขึ้น:
int max,i=1;
for(;i<max;i++){
Console.WriteLine(i);
}
ไปยัง
int max,i=1;
for(;i<max;){
Console.WriteLine(++i);
}
และนั่นจะลดลงด้วยตัวละครตัวหนึ่งและทำให้รหัสสับสนเล็กน้อยเช่นกัน ทำเช่นนั้นกับการi
อ้างอิงครั้งแรกเท่านั้นเช่น: (การเพิ่มประสิทธิภาพของตัวละครหนึ่งตัวมีไม่มากนัก แต่สามารถช่วยได้)
int max,i=1;
for(;i<max;i++){
Console.WriteLine(i + " " + i);
}
ไปยัง
int max,i=1;
for(;i<max;){
Console.WriteLine(++i + " " + i);
}
เมื่อลูปไม่จำเป็นต้องเพิ่มi
(วนกลับลำดับ):
for(int i=MAX;--i>0;){
Console.WriteLine(i);
}
++
ในกรณีดังกล่าวโดยตรงในส่วนหัวของลูป: for(;++i<max;)
ซึ่งง่ายต่อการติดตามและยากที่จะผิด
for
ส่วนหัวด้วยซึ่งจะบันทึกอักขระอีกครั้ง
for(;i<max;)
while(i<max)
จำนวนไบต์เท่ากัน แต่สำหรับฉันมันดูสะอาดกว่า
มีสถานการณ์เมื่อพารามิเตอร์เอาต์พุตสามารถบันทึกอักขระได้ นี่คือตัวอย่างที่มีการวางแผนเล็กน้อยอัลกอริทึมคะแนนโบว์ลิ่ง 10 พิน
ด้วยคำสั่งส่งคืน:
........10........20........30........40........50........60........70........80........90.......100.......110.......120.......130.......140.......150..
public double c(int[]b){int n,v,i=0,X=10;double t=0;while(i<19){n=b[i]+b[i+1];v=b[i+2];t+=(n<X)?n:X+v;if(b[i]>9)t+=b[i+(i>16|v!=X?3:4)];i+=2;}return t;}
และด้วยพารามิเตอร์ขาออก:
........10........20........30........40........50........60........70........80........90.......100.......110.......120.......130.......140.......
public void d(int[]b,out double t){int n,v,i=0,X=10;t=0;while(i<19){n=b[i]+b[i+1];v=b[i+2];t+=(n<X)?n:X+v;if(b[i]>9)t+=b[i+(i>16|v!=X?3:4)];i+=2;}}
พารามิเตอร์เอาต์พุตที่นี่บันทึกทั้งหมด 5 อักขระ
ใน C # เราไม่ได้รับอนุญาตให้ทำการif(n%2)
ตรวจสอบว่าn
เป็นเลขคู่หรือไม่ cannot implicity convert int to bool
ถ้าเราทำเราได้รับ การจัดการที่ไร้เดียงสาจะทำ:
if(n%2==0)
วิธีที่ดีกว่าคือใช้:
if(n%2<1)
ผมใช้วิธีนี้จะได้รับหนึ่งไบต์ที่นี่
โปรดทราบว่าวิธีนี้ใช้งานได้กับจำนวนบวกเท่านั้นเนื่องจาก-1%2==-1
จะได้รับการพิจารณาด้วยวิธีนี้
การปรับปรุงการประหยัดพื้นที่อย่างง่าย ๆ คือการแก้ไข แทน:
string.Format("The value is ({0})", (method >> 4) + 8)
เพียงใช้$
ในการแสดงออกแบบอินไลน์:
$"The value is ({(method >> 4) + 8})"
สิ่งนี้พร้อมกับนิพจน์เนื้อความใหม่ใน C # 6.0 ควรทำให้การคำนวณสตริงง่าย ๆ สามารถเล่นกอล์ฟได้ใน C #
i+$" bottles of beer";
$"{i} bottles of beer"
$
ไป
{i}
หนึ่งในด้านหน้าและเป็นหนึ่งในกลาง;)
ใช้ C # lambda เนื่องจาก PPCG อนุญาตแลมบ์ดาสำหรับอินพุต / เอาท์พุตเราจึงควรใช้มัน
วิธีการแบบคลาสสิก C # มีลักษณะเช่นนี้:
bool Has(string s, char c)
{
return s.Contains(c);
}
ในฐานะแลมบ์ดาเราจะเขียน
Func<string, char, bool> Has = (s, c) => s.Contains(c);
แลมบ์ดานิรนามได้รับอนุญาตเช่นกัน:
(s, c) => s.Contains(c)
ลบเสียงรบกวนและโฟกัส!
ปรับปรุง:
เราสามารถปรับปรุงขั้นตอนหนึ่งที่มากขึ้นด้วยความดีความชอบเป็นความคิดเห็น @TheLethalCoder:
s => c => s.Contains(c);
ตัวอย่างของการประมวลผลโดย @Felix Palmen: คำนวณคีย์ WPA อย่างไร
มันจะมีประโยชน์เมื่อคุณมีพารามิเตอร์ 2 ตัวแน่นอนตัวแปรที่ไม่ได้ใช้_
จะว่างเปล่าจะดีกว่า ดูโพสต์เมตาเกี่ยวกับเรื่องนี้ ผมใช้เคล็ดลับนี้ที่นี่ คุณจะต้องเปลี่ยนฟังก์ชั่นเล็กน้อย ตัวอย่าง: ลองออนไลน์!
s=>c=>...
s=>s.Contains
.
(string s,char c)=>s.Contains(c)
ทำให้ชื่อคลาสเป็นตัวอักษรเดียว การปรับปรุงเคล็ดลับสำหรับการเล่นโค้ดใน C # ที่เราทำได้
class Default{static void Main()
ไปยัง
class D{static void Main()
ซึ่งเคาะออกไปอีก 6 ตัวอักษรในกรณีนี้
Compute
วิธีการเช่นการSystem.Data.DataTable
ช่วยให้การประเมินนิพจน์สตริงง่ายเช่น:
namespace System.Data
{
class P
{
static void Main()
{
Console.Write(new DataTable().Compute("30*2+50*5/4",""));
}
}
}
ไม่มาก "Golfy" ต่อ se แต่บางครั้งอาจมีประโยชน์
โดยปกติในการสลับสองตัวแปรคุณต้องประกาศตัวแปรชั่วคราวเพื่อเก็บค่า มันจะดูเหมือนอะไรบางอย่างตามสายของสิ่งนี้:
var c=a;a=b;b=c;
นั่นคือ 16 ไบต์! มีวิธีการแลกเปลี่ยนอื่น ๆ ที่ดีกว่า
//Using tuples
(a,b)=(b,a);
//Bitwise xoring
a=a^b^(b=a);
//Addition and subtraction
a=a+b-(b=a);
//Multiplication and division
a=a*b/(b=a);
สามรายการสุดท้ายทำงานเฉพาะค่าตัวเลขและตามที่ ASCII ระบุอย่างชัดเจนเท่านั้นสองรายการสุดท้ายอาจส่งผลให้เกิดข้อยกเว้น ArithmeticOverflow ทั้งหมดข้างต้นคือ 12 ไบต์การประหยัด 4 ไบต์เปรียบเทียบกับตัวอย่างแรก
การใช้ LinqPad จะทำให้คุณสามารถลบค่าโสหุ้ยโปรแกรมทั้งหมดในขณะที่คุณสามารถรันคำสั่งได้โดยตรง (และควรเป็น codegolf อย่างถูกกฎหมาย ... ไม่มีใครบอกว่าคุณต้องการ. exe)
เอาท์พุททำได้โดยใช้.Dump()
วิธีการขยาย
.Dump()
;)
(กรณีใดกรณีหนึ่งที่รู้ว่าผู้ให้บริการของคุณมีความสำคัญ !)
ใช้%
สำหรับการลบแบบ จำกัด (ค่อนข้าง) จำกัด สิ่งนี้สามารถช่วยคุณประหยัดค่าวงเล็บคู่หนึ่งรอบการลบซึ่งผลลัพธ์ที่คุณต้องการคูณหรือหารด้วยบางสิ่ง แต่ระวังมันมีข้อ จำกัด ร้ายแรง
แทน
char b='5'; // b is some ASCII input
int a=(b-48)*c; // we want to find the numerical value of b, and multiply it by something ('0'==48)
พิจารณา
char b='5'; // b is some ASCII input
int a=b%48*c; // only good for ASCII within 48 of '0' (positive only)!
ตัวอย่าง:
'5'%'0'*2 -> 10
'5'%'0'*-1 -> -5
'5'%'0'/2 -> 2
ฉันเพิ่งค้นพบสิ่งนี้และฉันรู้สึกว่ามันจะเป็นสิ่งที่มีค่าที่จะจำเมื่อใดก็ตามที่ทำงานกับ ASCII ในอนาคต (ขณะนี้ฉันกำลังเล่นกอล์ฟที่ไหนสักแห่งที่ฉันใช้ ASCII สำหรับการแทนค่าตัวเลขขนาดกะทัดรัด แต่ต้องคูณด้วย1
หรือ-1
ขึ้นอยู่กับเงื่อนไขอื่นและสไทรพ์ 2 ไบต์นี้)
หากคุณต้องการรวมหลาย ๆ อย่างusing
ที่หลุดออกมาจากลำดับชั้นเดียวกันบ่อยครั้งที่สั้นลงเพื่อใช้อันที่ยาวที่สุดเป็นnamespace
:
using System;
using System.Linq;
//Some code
VS:
namespace System.Linq
{
//Some code
}
ค้นพบคืนนี้ "ในสนามเพลาะ" ในขณะที่การปรับปรุงรหัสกอล์ฟบางส่วน ... หากคุณมีชั้นเรียนสำหรับการประมวลผลของคุณคุณสามารถทำงานในตัวสร้างเพื่อบันทึกวิธีการประกาศ
ฉันค้นพบสิ่งนี้ในขณะที่ลดแอปพลิเคชันคอนโซล - เนื่องจากมีstatic void Main()
ฟังก์ชั่นและตัวแปรทั้งหมดจะต้องประกาศคงที่ ฉันสร้างคลาสที่ซ้อนกันด้วยฟังก์ชั่นสมาชิกและตัวแปรโดยมีงานหลักดำเนินการในตัวสร้าง สิ่งนี้จะบันทึกอักขระในรหัสการโทรด้วย
เช่น Class ด้วยเมธอด:
class a
{
public void b()
{
new c().d("input");
}
}
class c
{
public void d(string e)
{
System.Console.Write(e.Replace("in", "out"));
}
}
คลาสกับงานในตัวสร้าง:
class a
{
public void b()
{
new c("input");
}
}
class c
{
public c(string e)
{
System.Console.Write(e.Replace("in", "out"));
}
}
ตัวอย่างนี้บันทึก 9 อักขระ
ใช้Action
like Func
เพื่อตั้งค่าฟังก์ชั่นเป็นตัวแปร Action
ไม่ส่งคืนอะไร ( void
) จึงเหมาะสำหรับการพิมพ์
ตัวอย่างเช่น:
Action<string>w=Console.WriteLine;
w("Hello World");
เคล็ดลับนี้เป็นแรงบันดาลใจ @ W0lf ตัวอย่างที่ดีของการใช้Func
ReadLine
ด้วย
หากคุณต้องการประกาศสตริงว่าง / จับคู่หลายชุดคุณสามารถบันทึกสองสามไบต์ด้วยวิธีต่อไปนี้:
string a="";string b="";string c=""; // 36 bytes
var a="";var b="";var c=""; // 27 bytes
string a="",b="",c=""; // 22 bytes
string a="",b=a,c=a; // 20 bytes
น่าเสียดายที่var a="",b=a,c=a;
ผิดกฎหมายตามimplicitly type variable cannot have multiple declarators
var a=b=c=""
ชอบใน javascript ได้ไหม?