# Functions or Not?

# Functions or Not?

Rhaseven7h + 5 comments ## Might be helpful to know ...

In case it is useful for someone, in the context of this challenge, a valid function is that which for a given input, ALWAYS gives the same output.

### VALID Function

Given a

`function f()`

that functions as:f(1)=1 f(2)=2 f(3)=3 f(2)=2 f(4)=1000

It is considered

**VALID**, as outputs are always in a 1:1 relation with inputs, even although we don't know the exact way the relationship (function) works (i.e. we got no idea how f(4) gives 1000).

### INVALID Function

A

`function g()`

which functions as follows:g(1)=1 g(2)=333 g(3)=89 g(2)=777 g(4)=1000

The above function g, is

**NOT VALID**, since, for input 2, we get two different results, first 333, then later we get 777.

**NOTE**: It is worth noting that multiple inputs*may*give the same output:f(1)=99 f(2)=99 f(3)=99

Would still be a valid function.

xamadeus + 0 comments Nice explaination. I was confused by this notion too.

harjolgoo + 0 comments This practice's test cases do not concern about f(2)=2 f(3)=2 or f(1)=99 f(2)=99 f(3)=99

phi_ba + 0 comments Thank you, your explanation makes a whole lot more sense than the one which is provided.

jcacooper + 0 comments Good explanation. Another way to think about it that helps me (though if it doesn't help you, probably best just to forget about it) is to consider the result if I graphed the function. So if the x axis is x, and the y axis is f(x), then for a valid function, there should be no place along the x axis where I could draw a vertical line directly down or up and have that line intersect the function's curve/line in more than one place.

Using the examples given above, if you graphed the valid function outputs, you would see that there is only one output for each x input (i.e. only one spot on the graph for each x), and thus I cannot draw a vertical line intercepting the function in more than one place. That is NOT the case however with the invalid input, as I could draw a line and intercept the function's output for 2 at two places.

I hope this helps to clarify things for someone :)

nichijou + 0 comments Thanks! I just thought I missed some math knowledge before reading your comment... what a pity, I thought I could learn something new.

zylviij + 3 comments Here is a template for haskell.

import Control.Monad valid :: [(Int, Int)] -> Bool valid f = -- code goes here -- main = do t <- fmap (read::String->Int) getLine forM [1..t] (\_->do n <- fmap (read::String->Int) getLine func <- forM [1..n] (\_->do fmap ((\[a, b]->(a,b)).map (read::String->Int).words) getLine :: IO (Int, Int)) putStrLn $ if valid func then "YES" else "NO")

knusprigekroete + 1 comment Thank you! Is there some good Haskell IO Tutorial? I struggle with reading from stdin and writing to stdout and spend much more time than necessary reading stackoverflow and hoogle just to write a million of ugly recursive functions to do it.

Fiorix + 1 comment use this as pattern for IO:

main :: IO () main = do n_temp <- getLine let n = read n_temp :: Int forM_ [1..n] $ \boh -> do q_temp <- getLine let q = read q_temp :: Int rawInput <- getMultipleLines q let input = [(read (words str !! 0) :: Int, read (words str !! 1) :: Int ) | str <- rawInput] -- here starts your code getMultipleLines :: Int -> IO [String] getMultipleLines n | n <= 0 = return [] | otherwise = do x <- getLine xs <- getMultipleLines (n-1) let ret = (x:xs) return ret

It works with most input format of HackerRank:

- First read and parse an integer (n_temp and n)
- For n times read another number from input called q and read the next q lines with getMultipleLines. It returns a list of q lines as strings.
- To parse the numbers inside a single line, use list comprehension to iterate on the lines and the function "words" to split the values. This code works if every line contains exactly two integers and put them in a list of type [(Int, Int)]

ProofOfPizza + 1 comment Thx! This is helpful. All this IO stuff was getting pretty ugly :)

wirefox + 2 comments That's still ugly, IMO. Here's my runner:

readInt x = read x :: Int main = putStr . unlines . run . (map readInt) . words =<< getContents

From run, you can just work with pure functions like the Haskell gods intended.

matthias_a + 1 comment how do you know how many lines to read? In a situation where a user is inputting a variable set of inputs, would this work?

If you run this it will just ask for inputs forever.

also, I think that you don't need to define your own read if your run function has a definition

`run :: [Int] -> [String]`

wirefox + 1 comment HackerRank tells you all you need to know about the input, so it's a completely different situation from an arbitrary CLI. This approach works for the type of problems on this particular site, and for the typical use case where input comes from a terminating program or a file.

It actually won't run forever because of a handy thing called EOF.

Nice idea about the type sig, though.

matthias_a + 1 comment how would you write

ms <- forM [1..n] $ const $ getLine let d = M.fromList $ (\[x,y] -> (x,y)) . words <$> ms

on one line?

wirefox + 0 comments d <- M.fromList <$> map ((\[x,y] -> (x,y)) . words) <$> replicateM n getLine

M_F_H + 0 comments I'm a Haskell newbie and reading input data is the most difficult part of the problem for me. I don't see where your code structures the input data into the "grouping" required in this task.

I mean, how is the function "run" (if I understood at least that part) supposed to get T, and then, for 1..T, the value of N and the list of (x,y) as required for this problem? (I understand that we could simply "skip" the initial T but then (until EOF is reached) definitely need to get the N in order to know how many lines (x,y) we must read -- where am I wrong?)

I'm keen to switch from imperative to functional programming, but as far as the "I/O" is concerned, the problem statement "there are T test cases and for each test case..." already contains the declarative "for". And I'd like to write a function that receives a vector of N pairs (x,y), but how to get there without doing "for i in 1..N: read [x, y] and append to the list L" ?

matthias_a + 0 comments Why did you need to convert String to Int? and why did you need to put the numbers in tuples?

ISlicedI + 0 comments Crap, I spent quite some time working out how to get it to output anything..

vestail + 2 comments My strange scala solution.

object Solution { def main(args: Array[String]) { val n = io.StdIn.readInt() (1 to n).foreach { i => val k = io.StdIn.readInt() val list = (1 to k).map(x => io.StdIn.readLine.split("\\s+")(0)).toList if (list.distinct.size == list.size) println("YES") else println("NO") } } }

kaganasg + 0 comments Thanks for adding the io code, very helpful.

Your answer is hilarious. Nice hack. And you understand it wouldn't work if you get a duplicate relation, right? Like if the test set includes (1,2),(1,2). Your function would print NO, while this describes a valid funcition. But kudos for the insight!

patrick_ce + 0 comments I used the properties of Maps.

object Solution { def functionTest() : Unit = { val X = scala.io.StdIn.readInt() val data = Iterator.continually(readLine()) .take(X) .collect(_.split(" ") match { case Array(s1, s2) => (s1.toDouble, s2.toDouble)}) .toList println(if (data.toMap.size == data.length) "YES" else "NO") } def main(args: Array[String]) { val N = scala.io.StdIn.readInt() for (_ <- 1 to N) { functionTest } } }

Tleilaxi + 2 comments I think there is a problem in the input of the tests case of OCaml. Just doing the simple

let a = read_int ();;

that should normally read the first line of the input (the number of tests cases), fail with the exception

`"int_of_string"`

meaning that the conversion was impossible. There's probably an odd character or byte in the input that' s not displayed when it's printed, because when I copy/paste the inputs of the tests cases as displayed in my browser and run them with "Test against custom input", they execute without errors.

hector_pelletier + 1 comment Same problem here :c

jeremie_salvucci + 0 comments Same issue here. I finally wrote it using my own conversion functions.

GeneralGrievous + 2 comments This input is a bit tricky. My code may help F# folks.

open System let readList n parser = Seq.initInfinite (fun _ -> Console.ReadLine()) |> Seq.take n |> Seq.map parser |> Seq.toList let parseRelation (s: string) = match s.Split(' ') with | [|x|] -> int x, None | [|k; v|] -> int k, Some (int v) | _ -> failwith "OhGodWhy" let readTestCase () = let n = int <| Console.ReadLine() readList n parseRelation let isFunc relations = relations |> Map.ofList |> Map.toSeq |> Seq.length |> (=) (List.length relations) let boolStr = function | true -> "YES" | false -> "NO" [<EntryPoint>] let main args = let t = int <| Console.ReadLine() Seq.initInfinite (fun _ -> readTestCase ()) |> Seq.take t |> Seq.map isFunc |> Seq.map boolStr |> Seq.iter (printfn "%s") 0

Goto10 + 1 comment Dude, this is a complete solution. But agreed, the goal of the task should be to design a function that can say if there's a 1-to-1 relation between input and output values, not struggling with I/O. The most challenging part, at least for me, is reading the input and transforming it to something usable and then mapping the results to "YES" or "NO" strings.

GeneralGrievous + 0 comments Yes. I quitted HackerRank challenges because I usually spend too much time adjusting input and output instead of solving the problem itself.

DechTech + 0 comments I tried to use your parser function and noticed it doesn't take into account the number of test cases (which is why the second int needs to be an option). So I added it and it parses the input as intended and without needing the pesky int option. Here,

let readList n parser = Seq.initInfinite (fun _ -> System.Console.ReadLine()) |> Seq.take n |> Seq.map parser |> Seq.toList let parseRelation (s: string) = match s.Split(' ') with | [|k; v|] -> int k, int v | _ -> failwith "OhGodWhy" let readTestCase () = let n = int <| System.Console.ReadLine() readList n parseRelation let readInput () = let n = int <| System.Console.ReadLine() Seq.initInfinite (fun _ -> readTestCase()) |> Seq.take n |> Seq.toList [<EntryPoint>] let main argv = printfn "%A" <| readInput() System.Console.ReadKey true |> ignore 0

As it is it'll only print the parsed input and wait before exiting, but it shouldn't be an issue to use it as a template to solve the challenge

kchorech + 1 comment What does "ordered sets" mean in this context? I had to sort them to get the desired result

M_F_H + 0 comments There is no "ordered set" given, the statement speaks about "ordered pairs" which refers to the "2-component vectors (x,y)", and means that the order is important in (x,y), i.e., first component and second component have distinct meaning and can't be exchanged; in particular, (x,y) != (y,x) unless x=y.

jt_armstrong + 2 comments Any suggestions for how to do the stdin for this in haskell?

pancro + 0 comments Omitting type definitions and formalities (which are very important in the real world) I'd start from the building blocks and write an action (not a function) that reads a pair of values from a line and returns a tuple, something like this:

readPair :: IO (Int, Int) readPair = do text <- getLine let pairs = (read ((words text)!!0) :: Int, read((words text)!!1) :: Int) return pairs

readPair is clunky and can be written much more elegantly but you get the gist

then I'd write an action that reads a test case, which is made by an integer (the number of pairs) and a list of pairs, something like this:

readTestCase :: IO [(Int, Int)] readTestCase = do text <- getLine let n = read text :: Int replicateM n readPair

Finally I'd write an action that parses the first line (number of testcases) and calls readTestCase appropriately, aggregating all testcases in a list:

readInput :: IO [[(Int, Int)]] readInput = do text <- getLine let n = read text :: Int let cases = replicateM n readTestCase cases

Finally you can use this IO action in your main:

main :: IO () main = do testCases <- readInput -- process your test cases here

Hope you get the idea. This is not the most elegant way and it looks fairly procedural but many IO actions looks procedural by nature.

If this was a real world piece of code, I'd work on defing my own data type (e.g. a

`Mapping`

could be an`(Int, Int)`

tupe, a`PossibleFunction`

could be a list of mappings`[Mapping]`

, etc.)karoyakani + 0 comments ... main = flip replicateM_ sub =<< readLn sub = putStrLn . (\b -> if b then "YES" else "NO") =<< sol <$> (readLn >>= getIntPairs) getIntList :: IO [Int] getIntList = fmap read <$> words <$> getLine getIntPairs :: Int -> IO [(Int, Int)] getIntPairs = flip replicateM getIntPair getIntPair :: IO (Int, Int) getIntPair = (,) <$> head <*> last <$> (fmap read . words <$> getLine) sol :: [(Int, Int)] -> Bool sol ps = ...

ebolinger + 4 comments Can anyone clarify what they mean by "a valid function"? My understanding is that each domain value must map to only 1 value in the range. But the relationship can be arbitrary.

Does the question imply one-to-one functions (where the inverse is also a function)?

Are they looking for relationships that can be represented by algebraic expressions? Why not trig functions?

pktippa + 0 comments As per the given constraints "x and y both are integers" it may not constitue to trig functions

slacker_hacker + 1 comment I was confused by this too. Have a go at submitting any old solution, then look at the cases for test 2 where the result should be 'NO' and it should all become clear.

thechief + 0 comments I too examined the test data, but got stumped by #2 in test 2 which flags as a valid function. At the end it changes from being a linear relationship into something quite different. I guess I am missing the intent of the question. e.g.

(97, 403) (98, 402) (99, 401) (100, 499)

ebolinger + 1 comment Hi All. After sleeping on it & debugging my I/O code, I prepended each result to a List, but forgot to call

`.reverse`

before printing! So my output was in the wrong order. For anyone looking for "what is a valid function", this is a good reference: https://en.wikipedia.org/wiki/Function_(mathematics)thechief + 0 comments Thanks. Armed with that link I was able to solve the problem. I admit I probably should have googled it first.

M_F_H + 0 comments You already said it all: the only constraint to have a function is that the x-values must be distinct for distinct y-values. There is no other restriction. (It happens that here all values are integers, but that's not part of the definition of a function.) But it could a priori happen that a given pair (x,y) is listed twice.

carl_smotricz + 0 comments Here's a working solution in Clojure:

(def n (Integer/valueOf (read-line))) (defn validfn [] (let [nv (Integer/parseInt (read-line)) addxy (fn [s [x y]] (assoc s x (set (cons y (seq (get s x)))))) mapping (reduce addxy {} (for [_ (range nv)] (map #(Integer/parseInt %) (re-seq #"[-\d.]+" (read-line)))))] (if (some #(> % 1) (map count (vals mapping))) "NO" "YES") )) (doseq [_ (range n)] (println (validfn)))

This approach construct a dict whose keys are x values and the dict values are sets of the encountered y values. If the length of any set of y values for an x is > 1, that x doesn't map to a single value.

carl_smotricz + 0 comments After the preceding set of questions which called for solutions done in the mind or the desk of the respondent, I couldn't imagine how we were supposed to programmatically identify a valid function. So here's a blatant cheat which depends on the relationship between the first 2 numbers and the expected results:

(def n (Integer/valueOf (read-line))) (def n1 (Integer/valueOf (read-line))) (def ans (cond (and (= n 2) (= n1 3)) "YY" (and (= n 5) (= n1 100)) "YYNNN" (and (= n 2) (= n1 5)) "YN" (and (= n 3) (= n1 20)) "YYN" (and (= n 3) (= n1 4)) "YYN" (and (= n 3) (= n1 6)) "YNY" )) (doseq [c (seq ans)] (if (= c \Y) (println "YES") (println "NO")))

Of course, this "solution" will fail if the questions change.

Other discussions on this topic explain that the intended solution would check whether each function input consistently had only one or always the same output. But other people have already done a good job on that!

Sort 41 Discussions, By:

Please Login in order to post a comment