How to load images into an array of class? - c#

I have following code in which I wand to load images.
But whenever I Run the code other fields in collection are found empty and only one image is found in all collection data, & The following error is generated.
IndexOutOfRangeException: Index was outside the bounds of the array.
(wrapper stelemref) System.Object.virt_stelemref_class_small_idepth(intptr,object)
Below is my code :
[System.Serializable]
public class CollectionDataClass
{
public string name;
public string id;
public string thumbnail;
public Texture2D collectionImage;
}
[System.Serializable]
public class DataClass
{
[SerializeField] public CollectionDataClass[] collectionDataClass;
}
[SerializeField] private DataClass[] DataClassArray;
public IEnumerator BookCatogary(string reqParameter)
{
BookCatogaryBodyClass BookCatogryClass = new BookCatogaryBodyClass(reqParameter);
string json = JsonConvert.SerializeObject(BookCatogryClass);
Debug.Log("==========================>" + json);
var req = new UnityWebRequest(bookCategaryAPI, "POST");
byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);
req.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
yield return req.SendWebRequest();
if (req.isNetworkError)
{
Debug.Log("Error While Sending: " + req.error);
}
else
{
Debug.Log("Received: " + req.downloadHandler.text);
string temp = req.downloadHandler.text;
bookCatogaryObject = JsonConvert.DeserializeObject<BookCatogaryReceivedDataClass>(temp);
catogaryCount = bookCatogaryObject.Data.Rows.Count;
GetCatogariesName(catogaryCount);
GenerateCollectionData();
}
}
public void GenerateCollectionData()
{
DataClassArray = new DataClass[bookCatogaryObject.Data.Rows.Count];
for (int i = 0; i <= bookCatogaryObject.Data.Rows.Count; i++)
{
DataClassArray[i] = new DataClass();
DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];
for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
{
DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();
DataClassArray[i].collectionDataClass[m].name = bookCatogaryObject.Data.Rows[i].String[m].CollectionTitle;
DataClassArray[i].collectionDataClass[m].id = bookCatogaryObject.Data.Rows[i].String[m].Id;
DataClassArray[i].collectionDataClass[m].thumbnail = bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail;
StartCoroutine(DownloadImage(mediaUrl: DataClassArray[i].collectionDataClass[m].thumbnail , bookCatogaryObject.Data.Rows[i].String.Count));
}
}
}
IEnumerator DownloadImage(string mediaUrl, int count)
{
UnityWebRequest request = UnityWebRequestTexture.GetTexture(mediaUrl);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
Debug.Log(request.error);
else
{
//collectionImage = ((DownloadHandlerTexture)request.downloadHandler).texture;
//collectionImageContainer[count] = collectionImage;
for (int i = 0; i <= bookCatogaryObject.Data.Rows.Count; i++)
{
DataClassArray[i] = new DataClass();
DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];
for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
{
DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();
DataClassArray[i].collectionDataClass[m].collectionImage = ((DownloadHandlerTexture)request.downloadHandler).texture;
}
}
}
}

This is not an answer to your question. I just wanted to show you how you can simplify code by using temp locals and object initializers. It also makes the code more efficient because it eliminates repeated indexing and member accesses. But more importantly, it makes the code more readable.
public async void GenerateCollectionData()
{
var rows = bookCatogaryObject.Data.Rows;
DataClassArray = new DataClass[rows.Count];
for (int i = 0; i < rows.Count; i++) {
var currentString = rows[i].String;
var dc = new DataClass {
collectionDataClass = new CollectionDataClass[currentString.Count]
};
DataClassArray[i] = dc;
for (int m = 0; m < currentString.Count; m++) {
var collection = currentString[m];
dc.collectionDataClass[m] = new CollectionDataClass {
name = collection.CollectionTitle,
id = collection.Id,
thumbnail = collection.CollectionThumbnail,
collectionImage = await GetImage(collection.CollectionThumbnail)
};
}
}
}

So finally I found the answer to above question, instead of using coroutines I used async Task to return downloaded texture to GenerateCollectionData() method.
Below is code for reference :
public async void GenerateCollectionData()
{
DataClassArray = new DataClass[bookCatogaryObject.Data.Rows.Count];
for (int i = 0; i < bookCatogaryObject.Data.Rows.Count; i++)
{
DataClassArray[i] = new DataClass();
DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];
for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
{
DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();
DataClassArray[i].collectionDataClass[m].name = bookCatogaryObject.Data.Rows[i].String[m].CollectionTitle;
DataClassArray[i].collectionDataClass[m].id = bookCatogaryObject.Data.Rows[i].String[m].Id;
DataClassArray[i].collectionDataClass[m].thumbnail = bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail;
DataClassArray[i].collectionDataClass[m].collectionImage =
await GetImage(bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail);
}
}
}
public static async Task<Texture2D> GetImage(string imageURL)
{
using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageURL))
{
var asyncOperation = www.SendWebRequest();
while (asyncOperation.isDone == false)
{
await Task.Delay(1000 / 30);
}
if (www.isNetworkError || www.isHttpError)
{
Debug.Log($"{www.error}, URL:{www.url}");
return null;
}
else
{
return DownloadHandlerTexture.GetContent(www);
}
}
}

Related

Reading /proc/stat values to get cpu usage throws DivideByZeroException

I have been following this stack overflow article :
Accurate calculation of CPU usage given in percentage in Linux?
It is written in different language so I decided to follow the logic and convert it to C#.
public class HardwareInfoManager : IHardwareInfoManager
{
private IConfiguration Configuration;
private List<long> oldCpuStatistics;
private List<long> newCpuStatistics;
public HardwareInfoManager(IConfiguration Configuration)
{
this.Configuration = Configuration;
oldCpuStatistics = new List<long>();
newCpuStatistics = new List<long>();
}
private decimal GetCPUUsage()
{
string cpuUsagePath = "//proc//stat";
StringBuilder sb = new StringBuilder();
if (File.Exists(cpuUsagePath) && oldCpuStatistics.IsNullOrEmpty())
{
SaveIntsFromFilePath(cpuUsagePath, oldCpuStatistics);
Task.Delay(200);
GetCPUUsage();
}
if (File.Exists(cpuUsagePath) && !oldCpuStatistics.IsNullOrEmpty())
{
SaveIntsFromFilePath(cpuUsagePath, newCpuStatistics);
var prevIdle = oldCpuStatistics[3] + oldCpuStatistics[4];
decimal idle = newCpuStatistics[3] + newCpuStatistics[4];
var prevNonIdle = oldCpuStatistics[0] + oldCpuStatistics[1] + oldCpuStatistics[2] + oldCpuStatistics[5] + oldCpuStatistics[6] + oldCpuStatistics[7];
decimal nonIdle = newCpuStatistics[0] + newCpuStatistics[1] + newCpuStatistics[2] + newCpuStatistics[5] + newCpuStatistics[6] + newCpuStatistics[7];
var prevTotal = prevIdle + prevNonIdle;
decimal total = idle + nonIdle;
var totalDifference = total - prevTotal;
var idleDifference = idle - prevIdle;
decimal cpuPercentage = (totalDifference - idleDifference / totalDifference) * 100;
cpuPercentage = Math.Round(cpuPercentage, 2);
return cpuPercentage;
}
else
{
return 0;
}
}
private List<long> SaveIntsFromFilePath(string path, List<long> longList)
{
var firstLineOfCPUFile = File.ReadAllLines(path).First();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < firstLineOfCPUFile.Length; i++)
{
//take first index of a number until it reaches a whitespace, add to an int array
if (Char.IsNumber(firstLineOfCPUFile[i]))
{
sb.Append(firstLineOfCPUFile[i]);
//start with this index until it reaches whitespace
}
if (Char.IsWhiteSpace(firstLineOfCPUFile[i]) && i > 5)
{
longList.Add(long.Parse(sb.ToString()));
sb.Clear();
//start with this index until it reaches whitespace
}
}
sb.Clear();
return longList;
}
}
Unable to debug this as it runs on a remote raspberry machine , it throws this error:
Job HardwareInfo.HardwareInfo threw an exception.
Quartz.SchedulerException: Job threw an unhandled exception. --->
System.DivideByZeroException: Attempted to divide by zero.
95% of the time it throws the exception because of the totaldifference being 0. In the other cases it works and throws the whole info such as this:
"TenantId":null,"Hostname":"DEV1\n","Temperature":66.218,"MemoryStats":{"MemoryTotal":"1985984
kB","MemoryFree":"1072468 kB","MemoryAvailable":"1438552
kB"},"CPUUsage":0.0
Please advise, I am stuck for 2 days on this now.
This is how I solved it.
public class HardwareInfoManager : IHardwareInfoManager
{
private IConfiguration Configuration;
private List<long> oldCpuStatistics;
private List<long> newCpuStatistics;
public HardwareInfoManager(IConfiguration Configuration)
{
this.Configuration = Configuration;
oldCpuStatistics = new List<long>();
newCpuStatistics = new List<long>();
}
public HardwareInfoDto GetHardWareInfo()
{
return new HardwareInfoDto()
{
TenantId = Configuration.GetValue<string>("TenantId"),
Hostname = GetHostName(),
Temperature = GetTemperature(),
MemoryStats = GetMemoryStats(),
CPUUsage = GetCPUUsage()
};
}
private string GetHostName()
{
string hostNameFilePath = "//etc//hostname";
if (File.Exists(hostNameFilePath))
{
return (File.ReadAllText(hostNameFilePath));
}
else
{
return "";
}
}
private decimal GetTemperature()
{
string temperatureFilePath = "//sys//class//thermal//thermal_zone0//temp";
if (File.Exists(temperatureFilePath))
{
decimal output = Convert.ToDecimal(File.ReadAllText(temperatureFilePath));
output /= 1000;
//string temperature = output.ToString() + "°C";
return output;
//var file= File.ReadAllLines();
}
else
{
return 0.00M;
}
}
private MemoryStatsDto GetMemoryStats()
{
MemoryStatsDto memoryStatsDto = new MemoryStatsDto();
string memoryStatsPath = "//proc//meminfo";
if (File.Exists(memoryStatsPath))
{
var file = File.ReadAllLines(memoryStatsPath);
//Skipping all lines we are not interested in
for (int i = 0; i < 3; i++)
{
int firstOccurenceOfDigit = 0;
var memoryLine = file[i];
//index of first number , start the string until the end and store it
for (int j = 0; j < memoryLine.Length; j++)
{
if (Char.IsNumber(memoryLine[j]))
{
firstOccurenceOfDigit = j;
break;
}
}
var memoryValue = memoryLine.Substring(firstOccurenceOfDigit);
switch (i)
{
case 0:
memoryStatsDto.MemoryTotal = memoryValue;
break;
case 1:
memoryStatsDto.MemoryFree = memoryValue;
break;
case 2:
memoryStatsDto.MemoryAvailable = memoryValue;
break;
default: break;
}
}
return memoryStatsDto;
}
else
{
memoryStatsDto.MemoryAvailable = "";
memoryStatsDto.MemoryFree = "";
memoryStatsDto.MemoryTotal = "";
return memoryStatsDto;
}
}
private decimal GetCPUUsage()
{
string cpuUsagePath = "//proc//stat";
StringBuilder sb = new StringBuilder();
if (File.Exists(cpuUsagePath) && oldCpuStatistics.IsNullOrEmpty())
{
oldCpuStatistics = SaveIntsFromFilePath(cpuUsagePath, oldCpuStatistics);
Thread.Sleep(10000);
GetCPUUsage();
}
if (File.Exists(cpuUsagePath) && !oldCpuStatistics.IsNullOrEmpty())
{
newCpuStatistics = SaveIntsFromFilePath(cpuUsagePath, newCpuStatistics);
var prevIdle = oldCpuStatistics[3] + oldCpuStatistics[4];
decimal idle = newCpuStatistics[3] + newCpuStatistics[4];
var prevNonIdle = oldCpuStatistics[0] + oldCpuStatistics[1] + oldCpuStatistics[2] + oldCpuStatistics[5] + oldCpuStatistics[6] + oldCpuStatistics[7];
decimal nonIdle = newCpuStatistics[0] + newCpuStatistics[1] + newCpuStatistics[2] + newCpuStatistics[5] + newCpuStatistics[6] + newCpuStatistics[7];
var prevTotal = prevIdle + prevNonIdle;
decimal total = idle + nonIdle;
var totalDifference = total - prevTotal;
var idleDifference = idle - prevIdle;
decimal cpuPercentage = 0;
Log.Logger.Information($"TotalDifference is {totalDifference}");
Log.Logger.Information($"IdleDifference is {idleDifference}");
cpuPercentage = (totalDifference - idleDifference) * 100M / (totalDifference);
cpuPercentage = Math.Round(cpuPercentage, 2);
return cpuPercentage;
}
else
{
return 0;
}
}
private List<long> SaveIntsFromFilePath(string path, List<long> longList)
{
var firstLineOfCPUFile = File.ReadAllLines(path).First();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < firstLineOfCPUFile.Length; i++)
{
//take first index of a number until it reaches a whitespace, add to an int array
if (Char.IsNumber(firstLineOfCPUFile[i]))
{
sb.Append(firstLineOfCPUFile[i]);
//start with this index until it reaches whitespace
}
if (Char.IsWhiteSpace(firstLineOfCPUFile[i]) && i > 5)
{
longList.Add(long.Parse(sb.ToString()));
sb.Clear();
//start with this index until it reaches whitespace
}
}
sb.Clear();
for (int i = 0; i < longList.Count; i++)
{
Log.Logger.Information($"LongList index {i} value is {longList[i]}");
}
return longList;
}
}

File already used by another process in a infinity loop

Hi I'm trying to create a code generator that automatically saves the code in a file but when I do it in an infinite loop it doesn't work I've already tried with lock(obj) but it doesn't work.
I have the error "This file is already being used by another process" in an infinite loop
class Generator
{
public static int maxDigit;
public static int codeNumber;
public static void start()
{
for (int i = 0; i < codeNumber; i++)
{
Generate(16, maxDigit);
}
}
public static void Generate(int length, int maxDigit)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[length];
var random = new Random();
int counDigit = 0;
int i = 0;
while (i < stringChars.Length)
{
char c = chars[random.Next(chars.Length)];
if ("0123456789".Contains(c) && counDigit < maxDigit)
{
counDigit++;
stringChars[i] = c;
i++;
}
else if (!("0123456789".Contains(c)))
{
stringChars[i] = c;
i++;
}
}
var finalString = new String(stringChars);
string filePath = #"Codes.txt";
using (StreamWriter sw = new StreamWriter(filePath, true))
{
sw.WriteLine(finalString);
}
}
}
You are opening the file on the start() then you are trying to open it again on the Generate method.
Try this:
public static void start()
{
for (int i = 0; i < codeNumber; i++)
{
//using (StreamWriter sw = File.AppendText("Codes.txt"))
{
Generate(16, maxDigit);
}
}
}
then call it using:
Generator.maxDigit = 9;
Generator.codeNumber = 4;
Generator.start();
then it generates Codes.txt
e0uhHvWadGpsHooy
njxQZ6NxN0fiEOYE
QTlZfyTGfHOfWAFJ
d2OXXzhJ1R39Z32d

How to get data from an object that was created with anonymous variables

I have a problem with the cycle and the object and I do not know how to get the data. I need to get the values from MySQL and create a HTML table:
[![enter image description here][1]][1]
Their tables will be several and they should be grouped by date. Here I have a problem with grouping, data acquisition, and rendering. Who can tell what is wrong?
```
private const int cols = 3;
private string header;
private string title;
private StringBuilder body=new StringBuilder(string.Empty);
public void PrintRes()
{
var ID =Cursor.GetFieldValue<int>("ID");
var cmdRec = SqlClient.Main.CreateCommand(#"
select r.res, r.ID,r.emp, kdk.FIO, cert.date from certres r
left join kdk on n_kdk=r.EMPL
left join cert on cert.id=r.ID
where r.ID=#ID"
, new SqlParam("ID", ID)).ExecObjects(new { res = 0, fio = string.Empty, date=DateTime.MinValue});
foreach (var c in cmdRec.GroupBy(x=>x.date))
{
for (int i = 0; i < cmdRec.Select(x=>x.date==c.Key.Date).Count(); i++)
{
//var titleHead= string.Format("<tr>{0}</tr>", c.Key);
}
}
}
public void CreateHtml(int cols,string[] captions)
{
cols = captions.Length;
StringBuilder sb=new StringBuilder(string.Empty);
foreach (var c in captions)
{
sb.AppendFormat("<th>{0}</th>", c);
}
var title=string.Format("№", "FIO","Result");
header = string.Format("<thead><tr>{0}</tr></thead>", sb.ToString());
}
public void AddRows(object[] values)
{
body.Append("<tr>");
for (int i = 0; i < values.Length; i++)
{
body.AppendFormat("<td>{0}</td>", values[i].ToString());
}
for (int i = 0; i < cols; i++)
{
body.Append("<tr></tr>");
}
body.Append("</tr>");
}
public string Html()
{
return string.Format("<table>{0}</table><table style=\"boarder:solid 1px;\">{1}<tbody>{2}</tbody></table>",
title,header,body.ToString());
}
[1]: https://i.stack.imgur.com/xvwG9.png

What function can I use instead of EditorUtility.GetAssetPath?

UnityEditor it is only meant to work in the Editor only, but I need to use a similar feature in the playing mode.
ObjMaterial objMaterial = new ObjMaterial();
objMaterial.name = mats[material].name;
objMaterial.textureName = AssetDatabase.GetAssetPath(mats[material].mainTexture);
materialList.Add(objMaterial.name, objMaterial);
Full code:
\\\\\\\\\\\\\\\\\\\
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
using System.Linq;
struct ObjMaterial
{
public string name;
public string textureName;
}
public class Menu : MonoBehaviour {
public int window;
void Start () {
window = 1;
}
private static int vertexOffset = 0;
private static int normalOffset = 0;
private static int uvOffset = 0;
private static string targetFolder = "ExportedObj";
private static string MeshToString(Component mf, Dictionary<string, ObjMaterial> materialList)
{
Mesh m;
Material[] mats;
if(mf is MeshFilter)
{
m = (mf as MeshFilter).mesh;
mats = mf.GetComponent<Renderer>().sharedMaterials;
}
else if(mf is SkinnedMeshRenderer)
{
m = (mf as SkinnedMeshRenderer).sharedMesh;
mats = (mf as SkinnedMeshRenderer).sharedMaterials;
}
else
{
return "";
}
StringBuilder sb = new StringBuilder();
sb.Append("g ").Append(mf.name).Append("\n");
foreach(Vector3 lv in m.vertices)
{
Vector3 wv = mf.transform.TransformPoint(lv);
sb.Append(string.Format("v {0} {1} {2}\n",-wv.x,wv.y,wv.z));
}
sb.Append("\n");
foreach(Vector3 lv in m.normals)
{
Vector3 wv = mf.transform.TransformDirection(lv);
sb.Append(string.Format("vn {0} {1} {2}\n",-wv.x,wv.y,wv.z));
}
sb.Append("\n");
foreach(Vector3 v in m.uv)
{
sb.Append(string.Format("vt {0} {1}\n",v.x,v.y));
}
for (int material=0; material < m.subMeshCount; material ++) {
sb.Append("\n");
sb.Append("usemtl ").Append(mats[material].name).Append("\n");
sb.Append("usemap ").Append(mats[material].name).Append("\n");
//See if this material is already in the materiallist.
try
{
ObjMaterial objMaterial = new ObjMaterial();
objMaterial.name = mats[material].name;
objMaterial.textureName = EditorUtility.GetAssetPath(mats[material].mainTexture);
//else
//objMaterial.textureName = null;
materialList.Add(objMaterial.name, objMaterial);
}
catch (ArgumentException)
{
//Already in the dictionary
}
int[] triangles = m.GetTriangles(material);
for (int i=0;i<triangles.Length;i+=3)
{
//Because we inverted the x-component, we also needed to alter the triangle winding.
sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
triangles[i]+1 + vertexOffset, triangles[i+1]+1 + normalOffset, triangles[i+2]+1 + uvOffset));
}
}
vertexOffset += m.vertices.Length;
normalOffset += m.normals.Length;
uvOffset += m.uv.Length;
return sb.ToString();
}
private static void Clear()
{
vertexOffset = 0;
normalOffset = 0;
uvOffset = 0;
}
private static Dictionary<string, ObjMaterial> PrepareFileWrite()
{
Clear();
return new Dictionary<string, ObjMaterial>();
}
private static void MaterialsToFile(Dictionary<string, ObjMaterial> materialList, string folder, string filename)
{
using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl"))
{
foreach( KeyValuePair<string, ObjMaterial> kvp in materialList )
{
sw.Write("\n");
sw.Write("newmtl {0}\n", kvp.Key);
sw.Write("Ka 0.6 0.6 0.6\n");
sw.Write("Kd 0.6 0.6 0.6\n");
sw.Write("Ks 0.9 0.9 0.9\n");
sw.Write("d 1.0\n");
sw.Write("Ns 0.0\n");
sw.Write("illum 2\n");
if (kvp.Value.textureName != null)
{
string destinationFile = kvp.Value.textureName;
int stripIndex = destinationFile.LastIndexOf('/');//FIXME: Should be Path.PathSeparator;
if (stripIndex >= 0)
destinationFile = destinationFile.Substring(stripIndex + 1).Trim();
string relativeFile = destinationFile;
destinationFile = folder + "/" + destinationFile;
Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);
try
{
//Copy the source file
File.Copy(kvp.Value.textureName, destinationFile);
}
catch
{
}
sw.Write("map_Kd {0}", relativeFile);
}
sw.Write("\n\n\n");
}
}
}
private static void MeshToFile(Component mf, string folder, string filename)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
{
sw.Write("mtllib ./" + filename + ".mtl\n");
sw.Write(MeshToString(mf, materialList));
}
MaterialsToFile(materialList, folder, filename);
}
private static void MeshesToFile(Component[] mf, string folder, string filename)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
{
sw.Write("mtllib ./" + filename + ".mtl\n");
for (int i = 0; i < mf.Length; i++)
{
sw.Write(MeshToString(mf[i], materialList));
}
}
MaterialsToFile(materialList, folder, filename);
}
private static bool CreateTargetFolder()
{
try
{
System.IO.Directory.CreateDirectory(targetFolder);
}
catch
{
return false;
}
return true;
}
void OnGUI () {
GUI.BeginGroup (new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 200));
if(window == 1)
{
if(GUI.Button (new Rect (10,30,180,30), "Экспортировать"))
{
if (!CreateTargetFolder())
return;
GameObject[] selection = GameObject.FindGameObjectsWithTag("Boat");
if (selection.Length == 0)
{
//EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
return;
}
int exportedObjects = 0;
ArrayList mfList = new ArrayList();
for (int i = 0; i < selection.Length; i++)
{
Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter)).Concat(selection[i].GetComponentsInChildren(typeof(SkinnedMeshRenderer))).ToArray();
for (int m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mfList.Add(meshfilter[m]);
}
}
if (exportedObjects > 0)
{
Component[] mf = new Component[mfList.Count];
for (int i = 0; i < mfList.Count; i++) {
mf [i] = (Component)mfList [i];
}
string filename = /*EditorApplication.currentScene +*/ "_" + exportedObjects;
int stripIndex = filename.LastIndexOf ('/');//FIXME: Should be Path.PathSeparator
if (stripIndex >= 0)
filename = filename.Substring (stripIndex + 1).Trim ();
MeshesToFile (mf, targetFolder, filename);
}
}
if(GUI.Button (new Rect (10,150,180,30), "Выход"))
{
window = 5;
}
}
if(window == 5)
{
GUI.Label(new Rect(50, 10, 180, 30), "Вы уже выходите?");
if(GUI.Button (new Rect (10,40,180,30), "Да"))
{
Application.Quit();
}
if(GUI.Button (new Rect (10,80,180,30), "Нет"))
{
window = 1;
}
}
GUI.EndGroup ();
}
}

How to eliminate repeating code in Sorting methods -C#

Please, help me to eliminate repeating code in "SortMG" and "SortByName" methods. It is basically the same text and it annoys me.
class Student
{
public string name;
public string major;
public double grade;
public string studyForm;
public Student(string name, string major, double grade, string studyForm)
{
this.name = name;
this.major = major;
this.grade = grade;
this.studyForm = studyForm;
}
}
class Program
{
static void SortMG(Student[] sortMG, int n)
{
int i, j;
Student tmpMG = new Student("","", 0, "");
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortMG[j].major.CompareTo(sortMG[i].major)<0)
{
//I'm asking about this part:
tmpMG.name = sortMG[j].name;
tmpMG.major = sortMG[j].major;
tmpMG.studyForm = sortMG[j].studyForm;
tmpMG.grade = sortMG[j].grade;
sortMG[j].name = sortMG[i].name;
sortMG[j].major = sortMG[i].major;
sortMG[j].studyForm = sortMG[i].studyForm;
sortMG[j].grade = sortMG[i].grade;
sortMG[i].name = tmpMG.name;
sortMG[i].major = tmpMG.major;
sortMG[i].studyForm = tmpMG.studyForm;
sortMG[i].grade = tmpMG.grade;
}
else if (sortMG[j].major.CompareTo(sortMG[i].major) == 0)
{
if (sortMG[j].grade > sortMG[i].grade)
{
//and this part:
tmpMG.name = sortMG[j].name;
tmpMG.major = sortMG[j].major;
tmpMG.studyForm = sortMG[j].studyForm;
tmpMG.grade = sortMG[j].grade;
sortMG[j].name = sortMG[i].name;
sortMG[j].major = sortMG[i].major;
sortMG[j].studyForm = sortMG[i].studyForm;
sortMG[j].grade = sortMG[i].grade;
sortMG[i].name = tmpMG.name;
sortMG[i].major = tmpMG.major;
sortMG[i].studyForm = tmpMG.studyForm;
sortMG[i].grade = tmpMG.grade;
}
}
}
}
}
static void SortByName(Student[] sortN, int n)
{
int i, j;
Student tmpN = new Student("", "", 0, "");
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortN[j].name.CompareTo(sortN[i].name) < 0)
{
//and this part:
tmpN.name = sortN[j].name;
tmpN.major = sortN[j].major;
tmpN.studyForm = sortN[j].studyForm;
tmpN.grade = sortN[j].grade;
sortN[j].name = sortN[i].name;
sortN[j].major = sortN[i].major;
sortN[j].studyForm = sortN[i].studyForm;
sortN[j].grade = sortN[i].grade;
sortN[i].name = tmpN.name;
sortN[i].major = tmpN.major;
sortN[i].studyForm = tmpN.studyForm;
sortN[i].grade = tmpN.grade;
}
}
}
}
}
It looks like you are "swapping" items by swapping their property values. Seems like you should be just swapping the items instead:
if (sortMG[j].grade > sortMG[i].grade)
{
//and this part:
tmpMG = sortMG[j];
sortMG[j] = sortMG[i];
sortMG[i] = tmpMG;
}
You could also move that swap into a function that you call from the three locations to reduce duplicate code further:
public void Swap(Student[] sortMG, int i, int j)
{
//TODO: add bounds/null hecking
var tmpMG = sortMG[j];
sortMG[j] = sortMG[i];
sortMG[i] = tmpMG;
}
You could save yourself a lot of work by using Linq.
For example you could sort a Student[] by Major with the following:
List<Student> students = new List<Student>()
{
new Student("Jose Mendez", "Math", 80, "Beta"),
new Student("Alex Bello", "Math", 90, "Alpha"),
new Student("Bob Junior", "EE", 100, "Charlie")
};
Student[] array = students.ToArray();
array = array.OrderBy(x => x.Major).ToArray();
It seems like you are asking for something like:
static void copyStudent(Student from, Student to)
{
Student tmpMG = new Student();
tmpMG.name = from.name;
tmpMG.major = from.major;
tmpMG.studyForm = from.studyForm;
tmpMG.grade = from.grade;
from.name = to.name;
from.major = to.major;
from.studyForm = to.studyForm;
from.grade = to.grade;
to.name = tmpMG.name;
to.major = tmpMG.major;
to.studyForm = tmpMG.studyForm;
to.grade = tmpMG.grade;
}
static void SortMG(Student[] sortMG, int n)
{
int i, j;
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (sortMG[j].major.CompareTo(sortMG[i].major)<0)
copyStudent(sortMG[j], sortMG[i]);
else if (sortMG[j].major.CompareTo(sortMG[i].major) == 0)
{
if (sortMG[j].grade > sortMG[i].grade)
copyStudent(sortMG[j], sortMG[i]);
}
}
}
}
static void SortByName(Student[] sortN, int n)
{
for (int i = 0; i < n - 1; i++)
for (int j = i; j < n; j++)
if (sortN[j].name.CompareTo(sortN[i].name) < 0)
copyStudent(sortN[j], sortN[i]);
}
why not use:
static void SortMG(Student[] sortMG, int n)
{
sortMG = sortMG.OrderBy(i => i.major).ThenBy(i=> i.grade).ToArray();
}
static void SortByName(Student[] sortN, int n)
{
sortN = sortN.OrderBy(i => i.name).ToArray();
}

Categories