“unknown”과“missing”값을 어떻게 변수에 저장하고“unknown”과“missing”의 차이를 유지해야합니까?


57

이것을 "학문적"질문으로 생각하십시오. 나는 때때로 NULL을 피하는 것에 대해 궁금해하고 있으며 이것은 만족스러운 해결책을 제시 할 수없는 예입니다.


때때로 측정이 불가능하거나 누락 된 것으로 측정을 저장한다고 가정 해 봅시다. NULL을 피하면서 "빈"값을 변수에 저장하고 싶습니다. 다른 경우에는 값을 알 수 없습니다. 따라서 특정 시간 프레임에 대한 측정 값을 갖는 경우 해당 기간 내의 측정 값에 대한 쿼리는 3 가지 유형의 응답을 반환 할 수 있습니다.

  • 당시의 실제 측정 (예 :을 포함한 모든 숫자 값 0)
  • A "실종"/ "빈"값 (즉, 측정이 완료되었고, 값이됩니다 알려져 그 시점에서 비어있는).
  • 알 수없는 값 (즉, 해당 시점에서 측정이 수행되지 않았습니다. 비어있을 수 있지만 다른 값일 수도 있습니다).

중요한 설명 :

get_measurement()"빈", "알 수 없음"및 "정수"유형의 값 중 하나를 리턴 하는 함수가 있다고 가정하십시오 . 숫자 값이 있으면 반환 값 (곱하기, 나누기 등)에서 특정 작업을 수행 할 수 있지만 NULL에서 이러한 작업을 사용하면 응용 프로그램이 중단되지 않으면 응용 프로그램이 중단됩니다.

예를 들어 (의사 코드)와 같은 NULL 검사를 피하면서 코드를 작성할 수 있기를 원합니다.

>>> value = get_measurement()  # returns `2`
>>> print(value * 2)
4

>>> value = get_measurement()  # returns `Empty()`
>>> print(value * 2)
Empty()

>>> value = get_measurement()  # returns `Unknown()`
>>> print(value * 2)
Unknown()

의 어느 것도 있습니다 print(더 널 (NULL)이 사용되지 않았다로) 문은 예외를 발생하지 않습니다. 따라서 비어 있고 알 수없는 값은 필요에 따라 전파되며 값이 실제로 "알 수 없음"인지 "비어 있는지"확인하는 것은 실제로 필요할 때까지 지연 될 수 있습니다 (어딘가에 값 저장 / 직렬화).


참고 : NULL을 피하고 싶은 이유는 주로 두뇌 맛보기입니다. 내가 일을 끝내고 싶다면 NULL을 사용하는 것에 반대하지 않지만, 그것들을 피하면 어떤 경우에는 코드를 훨씬 더 강력하게 만들 수 있다는 것을 알았습니다.


19
"측정 완료이지만 빈 값"과 "측정 없음"을 구별하고 싶은 이유는 무엇입니까? 실제로, "측정은되었지만 빈 값"이란 무엇을 의미합니까? 센서가 유효한 값을 생성하지 못했습니까? 이 경우 "알 수 없음"과 다른 점은 무엇입니까? 당신은 시간을 거슬러 올라가서 올바른 가치를 얻을 수 없을 것입니다.
DaveG

3
@DaveG 서버에서 CPU 수를 가져 오는 것으로 가정합니다. 서버가 꺼져 있거나 폐기 된 경우 해당 값이 존재하지 않습니다. 의미가없는 측정이 될 것입니다 ( "결측"/ "빈"은 최상의 용어가 아닐 수도 있습니다). 그러나 그 가치는 "무의미한"것으로 알려져 있습니다. 서버가 존재하지만 값을 가져 오는 프로세스가 충돌하면 서버를 측정하는 것이 유효하지만 "알 수없는"값이 생성되지 않습니다.
exhuma

2
@exhuma "해당 사항 없음"으로 설명하겠습니다.
Vincent

6
호기심에서 "빈"이 단순히 어떤 스케일의 0과 같지 않은 곳에서 어떤 종류의 측정을하고 있습니까? "알 수 없음"/ "누락"예를 들어 센서가 연결되지 않았거나 센서의 원시 출력이 어떤 이유로 든 쓰레기 일 경우 유용하지만 모든 경우에 "빈"은 더 일관성있게 생각할 수 있습니다. 으로 표시되는 0, []또는 {}(스칼라 0, 빈리스트 및 빈 맵 각각). 또한, "missing"/ "unknown"값은 기본적으로 정확히 무엇 null을위한 것 입니다. 그것은 거기 에 객체가 있을 있지만 존재하지 않음을 나타냅니다.
Nic Hartley

7
어떤 솔루션을 사용하든, 처음부터 NULL을 제거하려는 것과 비슷한 문제가 발생했는지 스스로에게 물어보십시오.
Ray

답변:


85

적어도 기능적인 언어로 이것을하는 일반적인 방법은 차별적 인 노동 조합을 사용하는 것입니다. 그런 다음 유효한 int 중 하나 인 값, "missing"을 나타내는 값 또는 "unknown"을 나타내는 값입니다. F #에서는 다음과 같이 보일 수 있습니다.

type Measurement =
    | Reading of value : int
    | Missing
    | Unknown of value : RawData

Measurement값은 다음이 될 것이다 Readingint 값 또는 함께, Missing또는 Unknown같은 원시 데이터 value(필요한 경우).

그러나 차별적 노동 조합 또는 이에 상응하는 언어를 지원하는 언어를 사용하지 않는 경우이 패턴이 많이 사용되지 않을 수 있습니다. 따라서 예를 들어 열거 형 필드가있는 클래스를 사용하여 세 가지 중 올바른 데이터를 포함하는 클래스를 사용할 수 있습니다.


7
OO 언어로 합계 유형을 수행 할 수 있지만 보일러 플레이트가 상당히
많아서

11
"[비 기능 언어에서]이 패턴은 그다지 쓸모가 없습니다"— OOP에서 매우 일반적인 패턴입니다. GOF는이 패턴의 변형이 있으며 C ++와 같은 언어는이를 인코딩하기위한 기본 구성을 제공합니다.
Konrad Rudolph

14
@jk. 그렇습니다, 그들은 세지 않습니다 (잘 생각합니다; 안전 부족으로 인해이 시나리오에서는 매우 나쁩니다). 나는 std::variant(그리고 그 영적 전임자들)을 의미 했다.
Konrad Rudolph

2
@Ewan 아니요,“측정은… 또는…의 데이터 유형입니다.”입니다.
Konrad Rudolph

2
@DavidArno DU가 없어도 OOP에는이를위한 "표준"솔루션이 있습니다.이 솔루션은 유효하고 유효하지 않은 값에 대한 서브 클래스가있는 수퍼 클래스 값을 갖습니다. 그러나 아마도 너무 멀리 갈 것입니다 (실제로 대부분의 코드 기반은 다른 답변에서 볼 수 있듯이 하위 클래스 다형성을 피하기 위해 플래그를 선호합니다).
Konrad Rudolph

58

모나드가 무엇인지 아직 모른다면 오늘 배우기에 좋은 날이 될 것입니다. 나는 여기에 OO 프로그래머를위한 부드러운 소개가있다 :

https://ericlippert.com/2013/02/21/monads-part-one/

귀하의 시나리오는 "아마도 모나드"에 대한 작은 확장 Nullable<T>이며 C # 및 Optional<T>기타 언어 로도 알려져 있습니다.

모나드를 나타내는 추상 유형이 있다고 가정 해 봅시다.

abstract class Measurement<T> { ... }

그리고 세 개의 서브 클래스 :

final class Unknown<T> : Measurement<T> { ... a singleton ...}
final class Empty<T> : Measurement<T> { ... a singleton ... }
final class Actual<T> : Measurement<T> { ... a wrapper around a T ...}

바인드 구현이 필요합니다.

abstract class Measurement<T>
{ 
    public Measurement<R> Bind(Func<T, Measurement<R>> f)
  {
    if (this is Unknown<T>) return Unknown<R>.Singleton;
    if (this is Empty<T>) return Empty<R>.Singleton;
    if (this is Actual<T>) return f(((Actual<T>)this).Value);
    throw ...
  }

이것으로부터이 간단한 바인드 버전을 작성할 수 있습니다 :

public Measurement<R> Bind(Func<A, R> f) 
{
  return this.Bind(a => new Actual<R>(f(a));
}

이제 끝났습니다. 당신은 Measurement<int>손이 있습니다. 당신은 그것을 두 배로하고 싶습니다 :

Measurement<int> m = whatever;
Measurement<int> doubled = m.Bind(a => a * 2);
Measurement<string> asString = m.Bind(a => a.ToString());

그리고 논리를 따르십시오. 경우가 m있다 Empty<int>다음 asStringIS Empty<String>, 우수한.

마찬가지로, 우리가 가지고 있다면

Measurement<int> First()

Measurement<double> Second(int i);

그런 다음 두 가지 측정을 결합 할 수 있습니다.

Measurement<double> d = First().Bind(Second);

다시, 경우가 First()있다 Empty<int>다음 d이다 Empty<double>등등.

핵심 단계는 바인드 작업을 올바르게하는 것 입니다. 그것에 대해 열심히 생각하십시오.


4
Monads는 (고맙게도) 이해하는 것보다 사용하기가 훨씬 쉽습니다. :)
Guran

11
@leftaroundabout : 정확하게 머리를 쪼개는 구별에 들어가고 싶지 않기 때문에; 원래 포스터에서 언급했듯이 많은 사람들이 모나드를 다룰 때 자신감이 부족합니다. 간단한 조작의 전문 용어가 포함 된 범주 이론적 특성은 자신감과 이해의 발달에 반대합니다.
에릭 리퍼 트

2
그래서 당신의 조언은 + 일부 상용구 코드 로 대체 Null하는 것 Nullable입니까? :)
Eric Duminil

3
@Claude : 튜토리얼을 읽어야합니다. 모나드는 특정 규칙을 따르고 일련의 작업을 함께 묶을 수있는 기능을 제공하는 일반 유형 Measurement<T>이므로이 경우 모나드 유형입니다.
Eric Lippert

5
@daboross : 스테이트 풀 모나드는 모나드를 도입하는 좋은 방법이라는 데 동의하지만, 상태를 모나드를 특징 짓는 것으로 생각하지 않습니다. 일련의 함수를 함께 묶을 수 있다는 사실이 매력적이라고 ​​생각합니다. 상태 저장은 구현 세부 사항 일뿐입니다.
Eric Lippert

18

이 경우 Null Object Pattern의 변형이 유용 할 것이라고 생각합니다.

public class Measurement
{
    private int value;
    private bool isUnknown = false;
    private bool isMissing = false;

    private Measurement() { }
    public Measurement(int value) { this.value = value; }

    public int Value {
        get {
            if (!isUnknown && !isMissing)
            {
                return this.value;
            }
            throw new SomeException("...");
        }                   
    }

    public static readonly Measurement Unknown = new Measurement
    {
        isUnknown = true
    };

    public static readonly Measurement Missing = new Measurement
    {
        isMissing = true
    };
}

이를 구조체로 바꾸고, Equals / GetHashCode / ToString을 재정의하고 int, 또는에서 암시 적 변환을 추가 할 수 있으며, NaN과 같은 동작을 원한다면 자체 산술 연산자를 구현할 수도 있습니다. Measurement.Unknown * 2 == Measurement.Unknown.

즉, C # Nullable<int>은 모든 것을 구현하지만 다른 유형의 nulls를 구별 할 수 없다는 유일한 경고가 있습니다 . 나는 Java 사람이 아니지만 Java OptionalInt와 비슷한 언어이며 다른 언어에는 Optional유형 을 나타내는 자체 기능이있을 수 있습니다 .


6
이 패턴에서 본 가장 일반적인 구현에는 상속이 포함됩니다. MissingMeasurement와 UnknownMeasurement의 두 하위 클래스가있을 수 있습니다. 부모 Measurement 클래스에서 메소드를 구현하거나 재정의 할 수 있습니다. +1
Greg Burghardt

2
Null 개체 패턴 의 요점이 유효하지 않은 값에서 실패하지 않고 오히려 아무것도하지 않습니까?
Chris Wohlert

2
이 경우 @ChrisWohlert 객체에는 실제로 Valuegetter를 제외한 메소드 가 없으므로 Unknown다시로 변환 할 수 없으므로 실패해야 합니다 int. 측정에 SaveToDatabase()메소드가있는 경우 현재 오브젝트가 널 오브젝트 (단일 톤과 비교하거나 메소드 대체를 통해) 인 경우 양호한 구현은 트랜잭션을 수행하지 않을 수 있습니다.
Maciej Stachowski

3
@MaciejStachowski 그래, 아무것도하지 말라고 말하지 않고 Null Object Pattern 이 적합하지 않다고 말하고있다 . 귀하의 솔루션은 괜찮을 수도 있지만 Null Object Pattern 이라고 부르지는 않습니다 .
Chris Wohlert '

14

문자 그대로 정수를 사용해야한다면 가능한 해결책은 하나뿐입니다. 가능한 값 중 일부를 '누락'및 '알 수 없음'을 의미하는 '마법의 숫자'로 사용하십시오.

예 : 2,147,483,647 및 2,147,483,646

'실제'측정을 위해 int가 필요한 경우 더 복잡한 데이터 구조를 만드십시오.

class Measurement {
    public bool IsEmpty;
    public bool IsKnown;
    public int Value {
        get {
            if(!IsEmpty && IsKnown) return _value;
            throw new Exception("NaN");
            }
        }
}

중요한 설명 :

클래스의 연산자를 오버로드하여 수학 요구 사항을 달성 할 수 있습니다.

public static Measurement operator+ (Measurement a, Measurement b) {
    if(a.IsEmpty) { return b; }
    ...etc
}

10
@KakturusOption<Option<Int>>
Bergi

5
@Bergi 당신은 아마 그것이 원격으로 받아 들일 수 있다고 생각할 수 없습니다 ..
BlueRaja-Danny Pflughoeft

8
@ BlueRaja-DannyPflughoeft 실제로 이것은 중첩 구조를 갖는 OP 설명에 매우 적합합니다. 받아 들일 수있게하기 위해 물론 적절한 타입 별칭 (또는 "newtype")을 소개 할 것입니다. 그러나 type Measurement = Option<Int>정수 나 빈 읽기 결과는 괜찮 Option<Measurement>습니다. 측정했을 수도 있습니다. .
Bergi

7
@arp "NaN 근처의 정수"? 그 말의 의미를 설명해 주시겠습니까? 숫자가 숫자가 아닌 무언가의 개념을 "거의"라고 말하는 것은 다소 반 직관적 인 것처럼 보입니다.
Nic Hartley

3
@Nic Hartley 우리 시스템에서 "자연적으로"가능한 가장 낮은 음의 정수 그룹은 NaN으로 예약되었습니다. 이 바이트는 합법적 인 데이터 이외의 다른 바이트를 나타내는 여러 가지 이유를 인코딩하기 위해이 공간을 사용했습니다. (수십 년 전, 몇 가지 세부 사항을 혼동했을 수도 있지만, 정수 값으로 넣어서 수학을 시도하면 NaN을 던질 수있는 비트 세트가 분명히 있습니다.
arp

11

변수가 부동 소수점 숫자 인 경우 IEEE754 (대부분의 최신 프로세서 및 언어에서 지원되는 부동 소수점 숫자 표준)는 잘 알려지지 않은 기능이지만 표준은 하나가 아니라 전체 제품군 을 정의합니다. 임의의 응용 프로그램 정의 의미에 사용할 수있는 NaN (숫자가 아님) 값입니다. 예를 들어 단 정밀도 부동 소수점에는 2 ^ {22} 유형의 유효하지 않은 값을 구별하는 데 사용할 수있는 22 개의 사용 가능한 비트가 있습니다.

일반적으로 프로그래밍 인터페이스는 인터페이스 중 하나만 노출합니다 (예 : Numpy 's nan). 명시 적 비트 조작 이외의 다른 방법을 생성하는 기본 제공 방법이 있는지 모르겠지만 몇 가지 하위 수준 루틴을 작성하는 것입니다. ( a == b하나의 NaN 인 경우 설계 상 항상 false를 반환 하기 때문에이를 구별 할 수있는 것도 필요 합니다.)

예를 들어, 당신은 당신이 사용하는 경우 발에서 자신을 촬영하는 위험하지 않습니다를 사용하여 올바르게 전파하기 때문에, 잘못된 데이터 신호를 무효 다움을 알리기 위해 자신의 "매직 넘버"개혁보다 더 나은 average()기능을하고 있는지 확인하는 것을 잊지 당신의 특별한 가치.

라이브러리가 애매 모호한 기능이기 때문에 라이브러리를 올바르게 지원하지 않는 유일한 위험은 nan다음과 같습니다.


6

David Arno의 대답 에 따라 OOP의 차별적 인 노조와 Scala, Java 8 기능 유형 또는 Vavr 또는 Fugue 와 같은 Java FP 라이브러리와 같은 객체 기능 스타일로 공정하게 느낄 수 있습니다. 자연스럽게 다음과 같이 작성하십시오.

var value = Measurement.of(2);
out.println(value.map(x -> x * 2));

var empty = Measurement.empty();
out.println(empty.map(x -> x * 2));

var unknown = Measurement.unknown();
out.println(unknown.map(x -> x * 2));

인쇄

Value(4)
Empty()
Unknown()

( 요점으로 전체 구현 )

FP 언어 또는 라이브러리는 Try(aka Maybe) (값 또는 오류 Either를 포함하는 객체 ) 및 (성공 값 또는 실패 값을 포함하는 객체 )와 같은 다른 도구도 제공합니다 .


2

알려진 문제와 알려진 신뢰할 수없는 측정의 차이점과 지원하려는 다운 스트림 프로세스의 차이점에 관심이있는 이유는 문제에 대한 이상적인 솔루션입니다. 이 경우 '다운 스트림 프로세스'에는 휴먼 오퍼레이터 또는 동료 개발자가 제외되지 않습니다.

단순히 "두 번째 풍미"의 널 (null)이 나오더라도 다운 스트림 프로세스 세트에 합리적인 동작 세트를 도출하기에 충분한 정보가 제공되지 않습니다.

다운 스트림 코드에서 발생하는 잘못된 동작의 소스에 대한 상황에 맞는 가정에 의존하는 경우,이를 나쁜 아키텍처라고합니다.

알려진 이유없이 실패 이유와 실패를 구별 할만큼 충분히 알고 있고 해당 정보가 미래의 행동에 영향을 줄 수있는 경우 해당 지식을 다운 스트림으로 전달하거나 인라인으로 처리해야합니다.

이것을 처리하기위한 몇 가지 패턴 :

  • 합계 유형
  • 차별적 노동 조합
  • 연산 결과를 나타내는 열거 형과 결과 필드를 포함하는 객체 또는 구조체
  • 정상적인 작동으로는 달성 할 수없는 매직 스트링 또는 매직 넘버
  • 이 사용이 관용적 인 언어의 예외
  • 이 두 시나리오를 구별하고 실제로 사용하는 데 아무런 가치가 없다는 것을 깨닫습니다. null

2

내가 우아한 해결책이 아닌 "일을 얻는 것"에 관심이 있다면, 빠르고 더러운 해킹은 단순히 "알 수 없음", "누락"및 "내 숫자 값의 문자열 표현"을 사용하는 것입니다. 문자열에서 변환하여 필요에 따라 사용합니다. 이 글을 쓰는 것보다 빠르며 적어도 일부 상황에서는 완전히 적합합니다. (이제 다운 보트 수에 베팅 풀을 형성하고 있습니다 ...)


"무엇을 해내다"고 언급 한 것에 찬성했습니다.
바베큐

4
일부 사람들은 이것이 NULL을 사용하는 것과 같은 문제를 겪고 있음을 알 수 있습니다. 즉, NULL 확인이 필요하지 않고 "알 수 없음"및 "결측"확인이 필요하지만 런타임에 충돌이 발생하여 당신이 확인을 잊어 버린 유일한 지표로서 불행. NULL 검사가 누락 되어도 린터가이를 잡을 수 있다는 이점이 있지만, 이로 인해 손실됩니다. "알 수 없음"과 "누락"의 차이를 추가하지만, 거기에서 NULL을
이깁니다

2

질문이 "단일 int를 반환하는 메소드에서 두 개의 관련되지 않은 정보를 어떻게 반환합니까? 반환 값을 확인하고 싶지 않으며 null이 잘못되어 사용하지 마십시오."

전달하고자하는 것을 살펴 보자. 왜 int를 줄 수 없는지에 대한 int 또는 non-int 이론적 근거 를 전달하고 있습니다. 이 질문은 두 가지 이유 만있을 것이라고 주장하지만 열거 형을 만든 사람은 누구나 목록이 커질 것임을 알고 있습니다. 다른 근거를 지정하는 범위는 의미가 있습니다.

처음에는 예외를 던지는 경우가 좋은 것처럼 보입니다.

호출자에게 리턴 타입이 아닌 특별한 것을 말하고 싶을 때 예외는 종종 적절한 시스템입니다 : 예외는 단지 오류 상태만을위한 것이 아니며, 당신이 왜 할 수 있는지 설명하기 위해 많은 맥락과 근거를 반환 할 수있게합니다. 오늘은 아니야

그리고 이것은 유일하게 보장 된 유효한 정수를 반환 할 수있게하는 유일한 시스템이며, int를 취하는 모든 int 연산자와 메소드는 null 또는 매직 값과 같은 유효하지 않은 값을 확인할 필요없이이 메소드의 반환 값을 수락 할 수 있습니다.

그러나 이름에서 알 수 있듯이 이것이 정상적인 비즈니스 과정이 아닌 예외적 인 경우 예외는 실제로 유효한 솔루션 일뿐 입니다.

그리고 try / catch와 handler는 null check와 같은 수준의 상용구입니다.

발신자가 try / catch를 포함하지 않으면 발신자의 발신자 등이 있어야합니다.


순진한 두 번째 단계는 "측정입니다. 음의 거리 측정은 가능하지 않습니다."라고 말합니다. 따라서 일부 측정 Y의 경우 다음에 대한 const를 가질 수 있습니다.

  • -1 = 알 수 없음
  • -2 = 측정 불가,
  • -3 = 답변 거부
  • -4 = 알지만 기밀
  • -5 = 달의 위상에 따라 달라집니다 (표 5a 참조).
  • -6 = 4 차원, 제목에 주어진 측정,
  • -7 = 파일 시스템 읽기 오류
  • -8 = 나중에 사용하기 위해 예약 됨
  • -9 = 사각 / 입방체이므로 Y는 X와 같습니다.
  • -10 = 모니터 화면이므로 X, Y 측정을 사용하지 않습니다. 화면 대각선으로 X를 사용합니다.
  • -11 = 영수증 뒷면에 측정 값을 기록하고 판독 할 수 없었지만 5 또는 17이라고 생각합니다.
  • -12 = ... 아이디어를 얻었습니다.

이것은 많은 오래된 C 시스템과 int에 대한 진정한 제약이있는 현대 시스템에서도 수행되는 방식이며 어떤 유형의 구조체 또는 모나드로 래핑 할 수 없습니다.

측정 값이 음수이면 데이터 유형을 더 크게 만들고 (예 : long int) 매직 값을 int 범위보다 높게 설정하고 디버거에 명확하게 표시되는 일부 값으로 시작하는 것이 이상적입니다.

하지만 마법의 숫자 만 사용하는 것이 아니라 별도의 변수로 사용하는 것이 좋습니다. 예를 들어 엄격한 타이핑, 유지 관리 및 기대치 준수.


세 번째 시도에서, 우리는 비 -int 값을 갖는 것이 일반적인 비즈니스 과정 인 경우를 살펴 봅니다. 예를 들어, 이러한 값의 모음에 정수가 아닌 여러 항목이 포함될 수 있습니다. 이는 예외 처리기가 잘못된 접근 방법 일 수 있음을 의미합니다.

이 경우 int와 이론적 근거를 전달하는 구조에 적합합니다. 다시 말하지만,이 이론적 근거는 위와 같은 구성 요소 일 수 있지만, 둘 다 동일한 int로 유지하는 대신 구조의 별개의 부분으로 저장합니다. 처음에는 이론적 근거가 설정되면 int가 설정되지 않을 것이라는 규칙이 있습니다. 그러나 우리는 더 이상이 규칙에 묶이지 않습니다. 필요한 경우 유효한 숫자에 대한 근거도 제공 할 수 있습니다.

어느 쪽이든, 당신이 그것을 호출 할 때마다 int가 유효한지 확인하기 위해 이론적 근거를 테스트하기 위해 상용구가 필요합니다. 이유가 가능하다면 int 부분을 꺼내서 사용하십시오.

여기서는 "null을 사용하지 마십시오"에 대한 추론을 조사해야합니다.

예외와 마찬가지로 null은 예외적 인 상태를 나타냅니다.

호출자가이 메소드를 호출하고 구조의 "합리적"부분을 완전히 무시하고 오류 처리없이 숫자를 예상하고 0을 얻으면 0을 숫자로 처리하여 잘못 처리합니다. 마법의 숫자를 얻으면 그 숫자를 숫자로 취급하고 잘못합니다. 그러나 null을 얻으면 제대로 수행되므로 넘어 집니다.

따라서이 메소드를 호출 할 때마다 반환 값을 확인해야하지만 대역 내 또는 대역 외에서 시도 / 캐치, "합리적"구성 요소에 대한 구조 확인, int 확인과 같은 유효하지 않은 값을 처리해야합니다. 마법의 숫자 또는 null에 대한 int 확인 ...

유효하지 않은 int와 "My dog가이 측정 값을 먹었습니다"와 같은 이론적 근거를 포함 할 수있는 출력의 곱셈을 처리하는 대안은 해당 구조에 대한 곱셈 연산자를 오버로드하는 것입니다.

... 그리고이 데이터에 적용될 수있는 응용 프로그램의 다른 모든 연산자를 오버로드하십시오.

... 그리고 int가 걸릴 수있는 모든 메소드를 오버로드하십시오.

... 그리고 모든 오버로드 에는 여전히 유효하지 않은 정수에 대한 검사 포함되어 있어야합니다. 따라서이 한 메소드의 반환 유형을 호출 할 때 항상 유효한 정수 인 것처럼 처리 할 수 ​​있습니다.

따라서 원래 전제는 여러 가지면에서 거짓입니다.

  1. 유효하지 않은 값이 있으면 값을 처리하는 코드의 어느 시점에서나 유효하지 않은 값을 확인하지 않아도됩니다.
  2. int 이외의 것을 반환하면 int를 반환하지 않으므로 int처럼 취급 할 수 없습니다. 연산자 오버로드를 사용하면 가장 할 수 있습니다 .
  3. 마법의 숫자 (NULL, NAN, Inf ... 포함)가있는 정수는 더 이상 정수가 아니며 가난한 사람의 구조체입니다.
  4. null을 피하면 코드가 더 강력 해지지 않으며 int의 문제를 숨기거나 복잡한 예외 처리 구조로 옮길 수 있습니다.

1

귀하의 질문의 전제를 이해하지 못하지만 다음은 액면가 답변입니다. 누락 또는 비우기의 경우 math.nan(숫자가 아님) 할 수 있습니다. 수학적 연산을 수행 할 수 있으며 math.nan그대로 유지 math.nan됩니다.

None알 수없는 값으로 (Python 's null)을 사용할 수 있습니다 . 어쨌든 알 수없는 값을 조작해서는 안되며 일부 언어 (Python은 그중 하나가 아닙니다)에는 특수 null 연산자가있어 값이 null이 아닌 경우에만 작업이 수행되고 그렇지 않으면 값이 null로 유지됩니다.

다른 언어에는 가드 조항 (예 : Swift 또는 Ruby)이 있고 Ruby에는 조건부 조기 리턴이 있습니다.

나는 이것을 몇 가지 다른 방식으로 파이썬에서 해결하는 것을 보았습니다.

  • 수치 정보는 일반적으로 개체에 관한 것이며 측정 시간을 가지기 때문에 래퍼 데이터 구조를 가지고있다. 래퍼는 __mult__알 수없는 값 또는 누락 된 값이 발생할 때 예외가 발생하지 않도록 마술 방법을 재정의 할 수 있습니다 . Numpy와 Pandas는 그러한 기능을 가지고있을 수 있습니다.
  • 센티넬 값 (예 : Unknown-1 / -2)과 if 문
  • 별도의 부울 플래그
  • 게으른 데이터 구조-함수가 구조에 대해 일부 작업을 수행 한 다음 실제 결과가 필요한 가장 바깥 쪽 함수가 반환됩니다.
  • 이전 파이프 라인과 비슷한 작동 지연 파이프 라인을 사용하지만 데이터 세트 또는 데이터베이스에서 사용할 수 있습니다

1

값이 메모리에 저장되는 방법은 언어 및 구현 세부 사항에 따라 다릅니다. 나는 당신이 의미하는 것은 객체가 프로그래머에게 어떻게 행동해야 하는가라고 생각합니다. (이것은 내가 질문을 읽는 방법이며, 내가 틀렸다면 말해주십시오.)

이미 질문에 대한 답변을 제안했습니다. 수학적 연산을 허용하고 예외를 발생시키지 않고 자신을 반환하는 자체 클래스를 사용하십시오. 널 검사를 피하기 위해 이것을 원한다고 말합니다.

해결 방법 1 : null 검사를 피하지 마십시오

Missing로 표현 될 math.nan
Unknown수있다None

값이 둘 이상인 경우 또는 filter()값이 아닌 값 또는 함수에 대해 무시하려는 값 에만 작업을 적용 할 수 있습니다 .UnknownMissing

단일 스칼라에서 작동하는 함수에 대해 null 검사가 필요한 시나리오를 상상할 수 없습니다. 이 경우 강제로 null 검사를 수행하는 것이 좋습니다.


해결 방법 2 : 예외를 포착하는 데코레이터 사용

이 경우, Missing올릴 수 MissingExceptionUnknown올릴 수있는 UnknownException작업은 그것을 수행 할 때.

@suppressUnknown(value=Unknown) # if an UnknownException is raised, return this value instead
@suppressMissing(value=Missing)
def sigmoid(value):
    ...

이 방법의 장점은의 특성이다 Missing와는 Unknown그들을 억제 할 수 있도록 명시 적으로 요청하는 경우에만 억제된다. 또 다른 장점은이 방법이 자체 문서화라는 것입니다. 모든 함수는 알 수 없거나 누락 된 것으로 예상되는지 여부와 함수의 방식을 보여줍니다.

함수를 호출 할 때 누락이 누락을 얻지 못할 것으로 예상되면 함수가 즉시 발생하여 자동 실패 및 호출 체인 누락을 전파하는 대신 오류가 발생한 위치를 정확하게 보여줍니다. 알 수 없음도 마찬가지입니다.

sigmoid여전히 호출 할 수 있습니다 sin그것은 기대하지 않더라도, Missing또는 Unknown때문에 sigmoid예외를 잡을 것 '의 데코레이터.


1
같은 질문에 대해 두 가지 답변을 게시하는 것이 무엇인지 궁금합니다 (이것은 이전 답변입니다 . 문제가 있습니까?)
gnat

@gnat이 답변은 저자가 보여주는 방식으로 수행해서는 안되는 이유를 제시하며, 두 개의 답변을 다른 아이디어와 통합하는 번거 로움을 피하고 싶지 않습니다. 독립적으로 읽을 수있는 두 개의 답변을 작성하는 것이 더 쉽습니다. . 나는 왜 당신이 다른 사람의 무해한 추론에 대해 그렇게 많은 관심을 가지는지 이해하지 못합니다.
noɥʇʎԀʎzɐɹƆ

0

서버에서 CPU 수를 가져 오는 것으로 가정합니다. 서버가 꺼져 있거나 폐기 된 경우 해당 값이 존재하지 않습니다. 의미가없는 측정이 될 것입니다 ( "결측"/ "빈"은 최상의 용어가 아닐 수도 있습니다). 그러나 그 가치는 "무의미한"것으로 알려져 있습니다. 서버가 존재하지만 값을 가져 오는 프로세스가 충돌하면 서버를 측정하는 것이 유효하지만 "알 수없는"값이 생성되지 않습니다.

이 두 가지 모두 오류 조건처럼 들리므로 여기서 가장 좋은 옵션은 get_measurement()두 가지를 모두 예외로 즉시 처리하는 것입니다 (예 : DataSourceUnavailableException또는 SpectacularFailureToGetDataException각각). 그런 다음 이러한 문제가 발생하면 데이터 수집 코드가 즉시 대응할 수 있으며 (예 : 후자의 경우 다시 시도) 데이터에서 데이터를 성공적으로 가져올 수있는 경우 get_measurement()에만를 반환 int해야합니다. 소스-그리고 당신 int은 유효 하다는 것을 알고 있습니다.

상황이 예외를 지원하지 않거나 예외를 많이 사용할 수없는 경우 별도의 출력을 통해 반환되는 오류 코드를 사용하는 것이 좋습니다 get_measurement(). 이것은 실제 출력이 입력 포인터에 저장되고 오류 코드가 반환 값으로 다시 전달되는 C의 관용적 패턴입니다.


0

주어진 답변은 훌륭하지만 여전히 비어있는 값과 알 수없는 값의 계층 적 관계를 반영하지 않습니다.

  • 가장 높은 것은 알려지지 않았다 .
  • 그런 다음 값을 사용하기 전에 먼저 비어 있어야합니다.
  • 마지막 으로 계산할 이옵니다.

추악한 (추상화가 실패했지만) 완전히 작동하는 것은 (Java)입니다.

Optional<Optional<Integer>> unknowableValue;

unknowableValue.ifPresent(emptiableValue -> ...);
Optional<Integer> emptiableValue = unknowableValue.orElse(Optional.empty());

emptiableValue.ifPresent(value -> ...);
int value = emptiableValue.orElse(0);

여기서 멋진 타입 시스템을 갖춘 기능적 언어가 더 좋습니다.

사실 : / 빈 누락 알 수없는 * 이 아닌 값은 일부 프로세스 상태, 일부 생산 파이프 라인의 오히려 일부를 보인다. 다른 셀을 참조하는 수식이있는 스프레드 시트 셀과 같은 Excel. 문맥 상 람다를 저장한다고 생각할 것입니다. 셀을 변경하면 모든 재귀 종속 셀을 다시 평가합니다.

이 경우 int 공급자가 int 값을 얻습니다. 빈 값은 int 공급자에게 빈 예외를 던지거나 비어있는 것으로 평가합니다 (재귀 적으로 위쪽으로). 주 공식은 모든 값을 연결하고 빈 값 (예외 / 예외)을 반환합니다. 알 수없는 값은 예외를 발생시켜 평가를 비활성화합니다.

변경 사항을 리스너에게 알리는 Java 바운드 속성과 같이 값을 관찰 할 수 있습니다.

요컨대 : 추가 상태가 비어 있고 알 수없는 값이 필요한 반복 패턴은 바인딩 된 속성 데이터 모델과 같은 스프레드 시트가 더 우수 할 수 있음을 나타냅니다.


0

예, 여러 다른 NA 유형 의 개념이 일부 언어로 존재합니다. 더 의미있는 통계적인 것에서 더 그렇습니다 (즉 , 실종시 불완전, 실종시 불완전, 실종시 불규칙 ).

  • 위젯 길이 만 측정하는 경우 '센서 오류'또는 '전원 차단'또는 '네트워크 오류'를 구분하는 것이 중요하지 않습니다 ( '숫자 오버플로'는 정보를 전달하지만)

  • 그러나 데이터 마이닝 또는 설문 조사에서 응답자에게 소득 또는 HIV 상태 등을 묻는 경우 '알 수 없음'의 결과는 '답변 거부'와 구별되며 후자를 대치하는 방법에 대한 이전의 가정은 경향이 있음을 알 수 있습니다 전자와 다릅니다. 따라서 SAS와 같은 언어는 여러 가지 다른 NA 유형을 지원합니다. R 언어는 아니지만 사용자는 종종 그 주위를 해킹해야합니다. 파이프 라인의 다른 지점에있는 NA를 사용하여 매우 다른 것을 나타낼 수 있습니다.

  • 단일 항목에 대해 여러 개의 NA 변수가있는 경우도 있습니다 ( "다중 대치"). 예 : 본인의 나이, 우편 번호, 교육 수준 또는 소득에 대해 잘 모르면 수입을 무시하기가 더 어렵습니다.

다른 NA 유형을 지원하지 않는 범용 언어로 다른 NA 유형을 나타내는 방법에 관해서는 일반적으로 사람들은 부동 소수점 NaN (정수 변환 필요), 열거 형 또는 센티넬 (예 : 999 또는 -1000)과 같은 것들을 정수 또는 범주 형 값. 일반적으로 명확한 답변이 없습니다. 죄송합니다.


0

R에는 결 측값 지원 기능이 내장되어 있습니다. https://medium.com/coinmonks/dealing-with-missing-data-using-r-3ae428da2d17

편집 : 내가 downvoted했기 때문에 조금 설명 할 것입니다.

통계를 처리하려는 경우 통계 전문가가 R을 작성하므로 R과 같은 통계 언어를 사용하는 것이 좋습니다. 결 측값은 학생들에게 전체 학기를 가르치는 큰 주제입니다. 그리고 결 측값에 대해서만 큰 책이 있습니다.

그러나 점이나 "누락"또는 기타와 같이 누락 된 데이터를 표시 할 수 있습니다. R에서는 누락으로 의미하는 것을 정의 할 수 있습니다 . 그것들을 변환 할 필요는 없습니다.

결 측값을 정의하는 일반적인 방법은로 표시하는 것 NA입니다.

x <- c(1, 2, NA, 4, "")

그런 다음 어떤 값이 누락되었는지 확인할 수 있습니다.

is.na(x)

그리고 결과는 다음과 같습니다.

FALSE FALSE  TRUE FALSE FALSE

보시다시피 ""누락되지 않았습니다. ""알 수없는 것으로 위협 할 수 있습니다. 그리고 NA누락되었습니다.


@Hulk, 다른 기능 언어는 결 측값을 지원합니까? 결 측값을 지원하더라도 한 줄의 코드로만 통계적 방법으로 값을 채울 수 없습니다.
ilhan

-1

*대신 운영자 의 기능을 변경할 수없는 이유가 있습니까?

대부분의 답변에는 일종의 조회 값이 포함되지만이 경우 수학 연산자를 수정하는 것이 더 쉬울 수 있습니다.

그런 다음 전체 프로젝트에서 비슷한 empty()/ unknown()기능 을 가질 수 있습니다 .


4
이것은 모든 작업자 에게 과부하를
파이프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.