Home > Back-end >  Checking if there is a value in the Array hierarchy
Checking if there is a value in the Array hierarchy

Time:10-23

I want to check if there is a value in a certain variable I have. Below I put an example of a logic that I want to achieve.

No matter how hard I tried, I was able to write a very sketchy code as a result of 3 hours of work and research, but it has nothing to do with what I want to achieve.

My Code:

const Files = [
    {
      Name: 'System',
      Type: 'directory',
      Value: [
        {
          Name: 'Main',
          Type: 'directory',
          Value: [
            {
              Name: 'Drivers',
              Type: 'directory',
              Value: [
                {
                  Name: 'Startup',
                  Type: 'file',
                  Value: new FileSystem.File('Startup', 0x1, 'test blah blah'),
                },
              ],
            },
          ],
        },
      ],
    },
  ];

BlahBlah.has(Files, 'System->Main->Drivers');
// [File]
BlahBlah.has(Files, 'System->Main->Drivers->Startup');
// File
BlahBlah.has(Files, 'System->Main->Drivers->AnyWhere');
// undefined
BlahBlah.has(Files, 'System->Main->AnyRandomDirectory');
// NaN

My Function:

function text2Binary(str: string, spliter: string = ' '): string {
  return str
    .split('')
    .map(function (char) {
      return char.charCodeAt(0).toString(2);
    })
    .join(spliter);
}

export function FileTypeFromNumber(e: number) {
  if (typeof e != 'number')
    try {
      e = Number(e);
    } catch (_) {
      return null;
    }

  return {
    0x1: {
      Name: 'Executable File',
      Extension: 'exe',
    },
    0x2: {
      Name: 'Text Document',
      Extension: 'txt',
    },
  }[e];
}

export type FileTypes =
  | 0x1
  | 0x2
  | 0x3
  | 0x4
  | 0x5
  | 0x6
  | 0x7
  | 0x8
  | 0x9
  | null;
export class File {
  Name: string;
  Type: {
    Name: string;
    Extension: string;
  };
  Content: string;
  Size: number;
  constructor(name: string, type: FileTypes, content: string) {
    this.Name = name;
    this.Type = FileTypeFromNumber(type);
    this.Content = content;
    this.Size = text2Binary(content, '').length;
  }
}

export class Directory {
  public Name: string;

  public Files: (File | Directory)[] = [];

  constructor(name: string) {
    this.Name = name;
  }

  addFile(file: File | Directory) {
    this.Files.push(file);
  }

  getFile(name: string): null | (File | Directory)[] {
    if (typeof name != 'string')
      try {
        name = String(name);
      } catch (_) {
        return null;
      }

    const Result = this.Files.filter((e) => e.Name == name);

    return Result.length == 0 ? null : Result;
  }

  getSize() {
    return this.Files.map((e) =>
      e instanceof Directory ? e.getSize() : e.Size
    ).reduce((a, b) => a   b, 0);
  }

  has(name) {
    return this.Files.some((e) => e.Name == name);
  }

  getJSON() {
    return this.Files.map((e) => ({ ...e }));
  }
}
interface x {
  Content: string;
  Name: string;
  Size: number;
  Type: string;
}

export function ConvertFromJSONtoDirectory(json: any[]) {
  return json.map((value) => {
    const isDirectory = value.Type == 'directory';
    if (!isDirectory) {
      return value.Value;
    }
    const self = new Directory(value.Name);
    ConvertFromJSONtoDirectory(value.Value).map((e) => self.addFile(e));
    return self;
  });
}

export default class DirectorySystem {
  Memory: Map<any, any>;
  Current: string | null;

  constructor(Current = null) {
    this.Memory = new Map();
    this.Current = Current;
  }

  addDirectory(directory: Directory): null | true {
    if (!(directory instanceof Directory)) return null;

    if (this.Memory.has(directory.Name)) return null;

    this.Memory.set(directory.Name, directory);
    return true;
  }

  getDirectory(DirectoryName: string): boolean | Directory {
    if (typeof DirectoryName != 'string')
      try {
        DirectoryName = String(DirectoryName);
      } catch (_) {
        return null;
      }

    const Result = this.Memory.has(DirectoryName);

    return Result ? this.Memory.get(DirectoryName) : Result;
  }

  getDirectoryCurrent() {
    if (this.Current == null) return this;
  }

  changeDirectory(by: -1 | 1, value: string) {
    if (by == -1) {
      if (this.Current == null) return null;

      if (this.Current.includes('->')) {
        this.Current = this.Current.split('->').slice(0, -1).join('->');
      } else {
        this.Current = null;
      }

      return this.Current;
    } else if (by == 1) {
      let Position = [this.Current, value].join('->');
      if (this.Current == null) {
        Position = Position.split('->').slice(1).join('->');
      }
      let Result = this.has(Position);
      console.log(Result);
    }
  }

  has(query: string) {
    try {
      return query.split('->').reduce((a, b) => {
        if (Array.isArray(a)) {
          const f = a.filter((e) => e['Name'] == b);
          if (a.length > 0) {
            return f['Files'];
          } else {
            return a;
          }
        }
        return a['Files'];
      }, this.getJSON());
    } catch (_) {
      return false;
    }
  }

  getJSON(): x[][] {
    return [...this.Memory.values()].reduce((a, b) => {
      a[b.Name] = b.getJSON();
      return a;
    }, {});
  }
}

Result: (Thanks Michael M. and chill 389cc for helping me understand the error)

has(
    query: string,
    overwrite = null
  ) {
    // If overwrite argument is not null, we are going use it.
    let files = overwrite == null ? this.getJSON() : overwrite;
    // Split string for getting more usable type with converting string to Array.
    const QueryParams = query.split('->').filter(String);
    // If we dont have no query, we can return current status.
    if (QueryParams.length == 0) return overwrite;
    if (Array.isArray(files)) {
      const SearchFor = QueryParams.shift();
      const Result = files.filter((e) => {
        if (e instanceof Directory) {
          const x = e.Name == SearchFor;
          return x ? e : false;
        }
        return e.Name == SearchFor;
      })[0];
      // If we cant find any indexing result
      if (!Result) return false;
      // We found a file and if we dont have any query this is mean we found it!
      if (Result instanceof File) return QueryParams.length == 0;
      // We found a Directory and we doesnt have any Query now, so we can return true.
      if (Result instanceof Directory && QueryParams.length == 0) return true;
      if (
        Result.Name != SearchFor ||
        (QueryParams.length != 0 && Result.Files.length == 0)
      )
        // If name not suits or still we has Query and not enough file for indexing.
        return false;
      // If nothing happens on upper section, return rescyned version of this function.
      return this.has(QueryParams.join('->'), Result.Files);
    } else {
      // If value is Object, Try Search param in object, and return it.
      const Result = files[QueryParams.shift()];
      return !Result ? false : this.has(QueryParams.join('->'), Result);
    }
  }

CodePudding user response:

I can't replicate all of your code, but does this help?

interface Entry {
  Name: string,
  Type: string,
  Value: Array<Entry> | any,
};

const Files = [
  {
    Name: "System",
    Type: "directory",
    Value: [
      {
        Name: "Main",
        Type: "directory",
        Value: [
          {
            Name: "Drivers",
            Type: "directory",
            Value: [
              {
                Name: "Startup",
                Type: "file",
                Value: "test", // change this to anything
              },
            ],
          },
        ],
      },
    ],
  },
];

function getEl(files: Array<Entry>, path: String) {
  let path_walk = path.split("->");

  let obj = files;
  for (let part of path_walk) {
    let found = false;
    for (let entry of obj) {
      if (entry.Name == part) {
        obj = entry.Value;
        found = true;
      }
    }
    if (!found) return undefined;
  }
  return obj;
}

console.log(getEl(Files, "System->Main->Drivers")); // => [ { Name: 'Startup', Type: 'file', Value: 'test' } ]
console.log(getEl(Files, "System->Main->Drivers->Startup")); // => "test"
console.log(getEl(Files, "System->Main->Drivers->AnyWhere")); // => undefined
console.log(getEl(Files, "System->Main->AnyRandomDirectory")); // => undefined

CodePudding user response:

There are some obvious problems, such as the fact that your example shows .has() being called with two arguments but it is defined in the class to only take in one. That being said, here is a function that, given a string query like you have and an array of objects like you have, would read the query and return if the array works for that query.

function has(fileSystem, query) {
  const arrayOfArgs = query.split('->')
  if (Array.isArray(fileSystem)) {
    for (let i = 0; i < fileSystem.length; i  ) {
      if (fileSystem[i]['Name'] === arrayOfArgs[0]) {
        if (arrayOfArgs.length === 1) {
          // element found
          return true; // replace this to return an actual value if that is desired.
        }
        if (fileSystem[i]['Type'] === 'directory') {
          // if not, recurse in if it is a directory
          return has(fileSystem[i]['Value'], arrayOfArgs.slice(1).join('->'));
        } else {
          // if it isn't a directory, don't try to recurse in
          return false;
        }
      }
    }
  }
  return false;
}

console.log(has(Files, 'System->Main->Drivers'));            // true
console.log(has(Files, 'System->Main->Drivers->Startup'));   // true
console.log(has(Files, 'System->Main->Drivers->AnyWhere'));  // false
console.log(has(Files, 'System->Main->AnyRandomDirectory')); // false

You'll have to add your own types to get it back to TypeScript and obviously I pulled it out of the class for easier testing but it should be pretty easy to re-implement.

  • Related