DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #204 - Partial Keys

Implement a function that takes an object as an argument, and returns a very similar object but with a special property. The returned object should allow a user to access values by providing only the beginning of the key for the value they want. For example if the given object has a key idNumber, you should be able to access its value on the returned object by using a key idNum or even simply id. Num and Number shouldn't work because we are only looking for matches at the beginning of a key.

Be aware that you could simply add all these partial keys one by one to the object. However, for the sake of avoiding clutter, we don't want to have a JSON with a bunch of nonsensical keys.

Also, if a key is tested that appears as the beginning of more than one key in the original object (e.g. if the original object had a key idNumber and idString and we wanted to test the key id) then return the value corresponding with whichever key comes first alphabetically. (In this case it would be idNumbers value because it comes first alphabetically.)

Example

let o = partialKeys({ abcd: 1 })

o.abcd === 1 // true
o.abc === 1 // true
o.ab === 1 // true
o.a === 1 // true

o.b === 1 // false!

Object.keys(o) // ['abcd'] 

Tests

partialKeys({
aaa: 1,
abc: 2,
dfg: 3,
def: 4,
dfgh: 5
})

Good luck!


This challenge comes from philidinius on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Top comments (4)

Collapse
 
mellen profile image
Matt Ellen-Tsivintzeli • Edited

Thanks to this Stack Overflow answer I learned about the JavaScript Proxy object:

let handler =
{
  get: function(target, name)
  {
    let keys = Object.keys(target).filter(key => key.startsWith(name)).sort();
    if(keys.length > 0)
    {
      return target[keys[0]];
    }
  }
}

const partialKeys = obj => new Proxy(obj, handler);

let d = {'world':'hello'};

let pd = partialKeys(d);

console.log(pd.w);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
vidit1999 profile image
Vidit Sarkar

Python approach

class ObjectSpecial:
    def __init__(self, dictLike):
        # sort the dictionary with respect to keys
        # so now keys will be sorted in alphabetical order
        self.dictLike = dict(sorted(dictLike.items()))


    def __getattr__(self, s):
        # if any key starts with s then return the corresponding value
        # if key not found return 0
        for k, v in self.dictLike.items():
            if(k.startswith(str(s))):
                return v
        return 0

partialKey = lambda dictLike : ObjectSpecial(dictLike)

d = {'abcd' : 1,'abbd' : 2, 'abdd' : 3}
o = partialKey(d)

print(o.a) # output : 2
print(o.ab) # output : 2
print(o.abcd) # output : 1
print(o.abd) # output : 3
print(o.k) # output : 0 as key not present
print(o.ac) # output : 0 as key not present
Collapse
 
avalander profile image
Avalander • Edited

Scala

import scala.language.dynamics

object PartialKeys extends App {
  case class Wrapper[T](obj: T) extends Dynamic {
    private val fields = obj.getClass.getDeclaredFields.toList
    fields foreach (_.setAccessible(true))

    // `selectDynamic` expands field access `object.field` into `object.selectDynamic("field")`
    def selectDynamic (name: String): Option[Any] = {
      fields find (_.getName.startsWith(name)) map (_.get(obj))
    }
  }

  object obj {
    val abcd = 1
  }

  val o = Wrapper(obj)

  println(o.abcd) // Some(1)
  println(o.abc)  // Some(1)
  println(o.ab)   // Some(1)
  println(o.a)    // Some(1)
  println(o.b)    // None
}
Collapse
 
vidit1999 profile image
Vidit Sarkar • Edited

Hope I have got the problem right.
Here is the C++ solution

#include <bits/stdc++.h>
using namespace std;

class ObjectSpecial{
    map<string, int> mapSpecial;
    public:
    // constructor
    ObjectSpecial(map<string, int> mapObject){
        this->mapSpecial = mapObject;
    }

    // cpp map already stores the keys in alphabetical order
    // so start from first and if we find a key that starts with the partial key
    // then return its value
    // if key not found then return 0
    int operator[](string s){
        for(auto it : mapSpecial){

            // check if key starts with the given partial key s
            // if true then return corresponding value
            if(it.first.rfind(s,0) == 0)
                return it.second;
        }
        return 0;
    }
};

ObjectSpecial partialKeys(map<string, int> m){
    return ObjectSpecial(m);
}

// main function
int main(){
    ObjectSpecial o = partialKeys({{"abcd",1},{"abbd", 2}});
    cout << o["abcd"] << "\n"; // output : 1
    cout << o["ab"] << "\n"; // output : 2
    cout << o["k"] << "\n"; // output : 0 as key is not present
    cout << o["abc"] << "\n"; // output : 1
    cout << o["abd"] << "\n"; // output : 0 as key is not present
    return 0;
}